Ask OpenAI for a transparent PNG (some prompts still produce a scene, but the alpha channel is there when you request it explicitly).

Fail-safe background removal if the model still paints a backdrop (run it through rembg on your server and return a truly transparent PNG).

Below is a drop-in API route that does both.

Server: Next.js API (OpenAI + rembg fallback)
// pages/api/generate-image.ts
import type { NextApiRequest, NextApiResponse } from "next";
import OpenAI from "openai";
import { Rembg } from "rembg-node"; // npm i rembg-node openai
import { PNG } from "pngjs";        // npm i pngjs

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! });
const rembg = new Rembg({ logging: false });

function pngHasTransparency(buf: Buffer): boolean {
  try {
    const png = PNG.sync.read(buf);
    if (!png.alpha) return false; // no alpha channel at all
    // quick heuristic: if every pixel is fully opaque, treat as “not transparent”
    const data = png.data;
    for (let i = 3; i < data.length; i += 4) {
      if (data[i] < 255) return true;
    }
    return false;
  } catch {
    return false;
  }
}

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    if (req.method !== "POST") return res.status(405).end();

    const { prompt, size = 1024, style = "photo" } = req.body || {};
    if (!prompt || typeof prompt !== "string") {
      return res.status(400).json({ error: "Missing prompt" });
    }

    // 1) Generate with OpenAI requesting a transparent PNG
    const positive =
      style === "photo"
        ? `${prompt}, subject isolated, product photo, center composition, no background, studio lighting, soft shadows`
        : `${prompt}, minimal flat icon, no background, clean silhouette, high contrast`;

    const out = await openai.images.generate({
      model: "gpt-image-1",
      prompt: positive,
      size: `${size}x${size}`,
      background: "transparent", // <-- request alpha PNG
    });

    const b64 = out.data?.[0]?.b64_json;
    if (!b64) return res.status(500).json({ error: "Image generation failed" });

    let pngBuf = Buffer.from(b64, "base64");

    // 2) Fallback: if there’s no transparency, strip background with rembg
    // (Some prompts still paint a solid scene; this guarantees alpha.)
    if (!pngHasTransparency(pngBuf)) {
      pngBuf = await rembg.remove(pngBuf);
    }

    // Return data URL
    const dataUrl = `data:image/png;base64,${pngBuf.toString("base64")}`;
    return res.status(200).json({ dataUrl });
  } catch (err: any) {
    console.error(err);
    return res.status(500).json({ error: err?.message ?? "Internal error" });
  }
}

Install & set env
npm i openai rembg-node pngjs
# in Replit Secrets:
#   OPENAI_API_KEY = sk-...

Client: no changes needed (just keep your existing call)

Your helper already posts to /api/generate-image. It will now return a truly transparent PNG every time. The checkerboard preview should show through (no grey/white squares trapped behind the subject).

If you still see a background, it’s likely the preview container’s CSS. Keep the checkerboard background on the container (not the <img>), and ensure the image class doesn’t set a background color.

<div
  className="rounded-lg border p-3 grid place-items-center"
  style={{
    background:
      "conic-gradient(#f8fafc 25%, #eef2f7 0 50%, #f8fafc 0 75%, #eef2f7 0) 0 0/16px 16px",
  }}
>
  <img src={iconUrl} alt="Generated icon" className="max-h-64 object-contain" />
</div>

Why they had backgrounds

Some prompts steer the model to render a full scene; even with background:"transparent" the content may include a “grey studio sweep”.

The rembg fallback removes that, guaranteeing a clean alpha PNG for your logo composer.