ScreenshotNeo

BlogHow-to

How to Use a Node.js Image Generation SDK

Generate and save images from Node.js with the OpenAI SDK. Set up credentials, choose output options, handle errors, and make the result usable in your app.

By the ScreenshotNeo team29 September 202612 min read

How to Use a Node.js Image Generation SDK

To generate an image from Node.js, install the official openai package, set OPENAI_API_KEY in the server environment, call client.images.generate(), decode the returned base64 data, and write the bytes to a file. Keep the key on the server. The example below uses the current Images guide’s SDK call and model identifier; check the live guide before deploying because model names and accepted options can change.

1. Install the SDK and configure your key

Use a supported server-side Node.js environment and npm. Create a small project and install the SDK:

mkdir node-image-demo
cd node-image-demo
npm init -y
npm install openai

Set the key in your shell rather than writing it into source code. On macOS or Linux:

export OPENAI_API_KEY="your_api_key_here"

In PowerShell, set it for the current session:

$env:OPENAI_API_KEY="your_api_key_here"

The SDK reads the environment variable when creating the client. Never put a secret key in frontend JavaScript, a public repository, a static site, or code delivered to a browser. For a deployed service, configure the variable through the hosting platform’s secret manager. The OpenAI quickstart documents this server-side setup.

2. Generate and save an image

Save this as generate.mjs. It requests one image, checks that image data was returned, converts the base64 string to bytes, and writes a PNG:

import OpenAI from "openai";
import { writeFile } from "node:fs/promises";

const client = new OpenAI();

const prompt = "An editorial illustration of a small greenhouse on a rainy city rooftop, soft natural light, detailed leaves";

const result = await client.images.generate({
  model: "gpt-image-2.5-sunburst",
  prompt,
  size: "1024x1024",
  quality: "medium",
  output_format: "png"
});

const image = result.data?.[0];
if (!image?.b64_json) {
  throw new Error("The image response did not contain image data");
}

const bytes = Buffer.from(image.b64_json, "base64");
await writeFile("generated.png", bytes);
console.log(`Saved ${bytes.length} bytes to generated.png`);

Run it with:

node generate.mjs

The current official guide shows the JavaScript SDK’s images.generate call and the data[0].b64_json image payload. The output is encoded image data, not a URL; decode it before saving or returning it. See the Image Generation guide for the current endpoint, models, options, and response details.

3. Choose model and output settings

Think about the result your application needs before setting output parameters. The same prompt may need different size, fidelity, and file format depending on whether it is a thumbnail, a portrait, a transparent asset, or a large hero image.

Choose dimensions, format, quality, and background to fit how the generated asset will be used.
Choose dimensions, format, quality, and background to fit how the generated asset will be used.
Setting Use it for Check before relying on it
model Selecting the image model for generation Model availability and accepted features can change. The current guide distinguishes its newer GPT Image models from earlier models.
prompt Describing the subject, style, composition, lighting, and constraints Specific visual instructions are easier to evaluate than vague requests. State what must be prominent and what to avoid.
size Choosing dimensions and aspect ratio Common guide examples include square, landscape, and portrait dimensions. Some current models accept custom dimensions under documented limits.
quality Trading image detail against cost and generation time Supported values depend on model. The current guide lists low, medium, high, and for some newer models xhigh and max; auto may also be supported.
output_format Choosing the resulting file encoding The reference lists PNG, JPEG, and WebP support for image output in relevant configurations. Match the extension to the selected format.
background Requesting opaque, automatic, or transparent output where available For transparent output, the current guide specifies PNG or WebP. Confirm that the chosen model accepts transparency.
output_compression Controlling compression for JPEG or WebP where supported Follow the current reference’s valid range; this does not apply to every output format.

For newer models, the live guide describes custom dimensions as strings such as 1536x864 and documents constraints: width and height must be multiples of 16, the aspect ratio must stay between 1:3 and 3:1, neither edge may exceed 3840 pixels, and total pixels must fall within the stated minimum and maximum. It also warns that resolutions above 2560×1440 are experimental. These rules are model-specific, so do not assume every older model accepts the same sizes.

Use auto only if the selected parameter supports it and automatic selection is acceptable to your product. Pin size and quality when you need consistent output characteristics. For transparent backgrounds, request transparency and choose PNG or WebP as the guide instructs; JPEG has no alpha channel.

4. Return generated images from an application

A command-line script can write directly to disk. In a web service, generate on the server and return either an image response or a reference to a stored asset. Here is a minimal Express route that returns PNG bytes. Install Express with npm install express, then save as server.mjs:

import express from "express";
import OpenAI from "openai";

const app = express();
app.use(express.json({ limit: "20kb" }));
const client = new OpenAI();

app.post("/images", async (req, res) => {
  const prompt = req.body?.prompt;
  if (typeof prompt !== "string" || prompt.trim().length === 0) {
    return res.status(400).json({ error: "prompt must be a non-empty string" });
  }

  try {
    const result = await client.images.generate({
      model: "gpt-image-2.5-sunburst",
      prompt: prompt.trim(),
      size: "1024x1024",
      quality: "medium",
      output_format: "png"
    });
    const encoded = result.data?.[0]?.b64_json;
    if (!encoded) return res.status(502).json({ error: "No image data returned" });

    const bytes = Buffer.from(encoded, "base64");
    res.set("Content-Type", "image/png");
    res.set("Cache-Control", "no-store");
    return res.status(200).send(bytes);
  } catch (error) {
    console.error("Image generation failed", error);
    return res.status(502).json({ error: "Image generation failed" });
  }
});

app.listen(3000, () => console.log("Listening on http://localhost:3000"));

Start the service with node server.mjs. The example intentionally does not expose upstream error text to anonymous clients, and it validates the prompt’s basic shape. A production endpoint should also authenticate callers, cap request size and frequency, and validate prompts according to the application’s requirements. If you store the output, use a controlled storage layer and return an application-owned asset URL rather than making every user request regenerate it.

5. Use cURL, Python, or Node.js

The SDK is convenient in Node.js, but the underlying API can also be called directly. These examples illustrate the generation endpoint and base64 decoding pattern; check the current image guide for the model and parameter choices accepted by your account.

cURL

curl -sS https://api.openai.com/v1/images/generations \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-image-2.5-sunburst","prompt":"A minimalist botanical illustration of a fern","size":"1024x1024","quality":"medium"}' \
  | jq -r '.data[0].b64_json' | base64 --decode > fern.png

This pipeline assumes jq and a base64 decoder are installed. Add set -o pipefail in a Bash script so an earlier request or parsing failure is not silently hidden by the final command. For robust automation, first save and inspect the HTTP response and status code; otherwise an API error JSON document can be mistaken for image data.

Python

Install the official package with pip install openai and use the environment variable in the same way:

from openai import OpenAI
import base64

client = OpenAI()
result = client.images.generate(
    model="gpt-image-2.5-sunburst",
    prompt="A minimalist botanical illustration of a fern",
    size="1024x1024",
    quality="medium",
)

image = result.data[0]
if not image.b64_json:
    raise RuntimeError("The response contained no image data")
with open("fern.png", "wb") as f:
    f.write(base64.b64decode(image.b64_json))

Node.js SDK

For an SDK-based Node application, use the first complete example above: npm install openai, initialize new OpenAI(), call client.images.generate(), and decode result.data[0].b64_json with Buffer.from(value, "base64"). Keep the SDK generation and decode steps on the server. The SDK can be initialized once and reused across requests rather than recreated for each image.

6. Prompt and response edge cases

  • No first image: The example checks for missing data before decoding. Do not index blindly if your code may encounter an unexpected or incomplete response.
  • Wrong file extension: If you request JPEG or WebP, write the matching extension and use the matching content type. A PNG suffix does not convert bytes to PNG.
  • Large outputs: Base64 adds overhead relative to raw bytes, so a large response temporarily occupies memory both as a string and as a decoded buffer. Avoid logging the base64 body. For high-volume workflows, consider how your storage path handles large buffers and request concurrency.
  • Prompt validation: Reject empty input and set reasonable application limits. Do not let user-provided input select arbitrary models, output settings, or spending behavior without validation.
  • Structured application output: Treat generated content as a binary asset. Store metadata such as prompt version, requested model, dimensions, format, and creation time separately if reproducibility or auditability matters.
  • Retries: Do not blindly retry every failure. A validation or authentication error will not be repaired by repetition, while a transient network or service failure may be retriable. Use bounded retries with backoff, and avoid duplicate user charges or duplicate jobs when your own workflow retries.

7. Streaming, latency, and throughput

For a simple script or a request that only needs the finished asset, use a normal generation call. Streaming is relevant when the interface benefits from intermediate image updates. The official image streaming reference describes partial image events and completed image events with base64 data; wire up the SDK’s exact JavaScript event types and payload shape from the current guide before shipping. Do not assume a stream yields one ordinary final response object.

Generation time depends on the chosen model, output dimensions, quality, and service conditions; the retrieved documentation does not establish a universal latency figure. Measure the end-to-end time in your own deployment and set a timeout suitable for the user experience. For interactive routes, communicate progress and provide a way to poll or retrieve a completed job if synchronous waiting would tie up the client connection. Limit parallel generations to a level your service and account can handle. Queue bulk work and apply backpressure instead of starting an unbounded number of requests.

Reuse the OpenAI client instance, keep response handling small, and resize or transform images in a separate step only when needed. Choosing smaller dimensions and lower quality can reduce output work; compare sample results for your own use case rather than assuming a particular quality level is sufficient.

8. Cost, reliability, and data handling

Image generation has an API cost; do not treat it as equivalent to a free local image transform. The research materials do not provide a decision-safe price or latency comparison, and pricing can change. Before release, consult the live pricing and model pages, calculate expected request volume and output settings, and set project spending controls. Cache or reuse an existing image when the request is identical and your product permits reuse. Track successful requests, failures, selected settings, and application-level retries so you can understand usage.

Use bounded retries for transient failures and surface a clear application error when a request cannot complete. Preserve the upstream request identifier and status in protected logs where available, but do not log API keys, complete base64 payloads, or sensitive prompts. A timeout does not always prove the provider did not complete work; avoid automatic retry loops that can duplicate generation. For longer or bulk workflows, a queue with idempotency at your application layer is easier to control than many concurrent web requests.

Data handling depends on the model and endpoint. OpenAI’s data-controls documentation specifically states that image generation with gpt-image-1 and gpt-image-1-mini is Zero Data Retention compatible, while DALL·E 2 and DALL·E 3 are not. That statement is scoped to those models and this compatibility designation; it is not a blanket guarantee about all API data handling. Review the current data controls documentation and applicable policies for your deployment.

9. Troubleshooting

Symptom Likely cause Fix
Missing API key or client initialization error OPENAI_API_KEY is unset in the process environment or is unavailable to the deployed service. Set the secret in the same shell or deployment environment that launches Node. Restart the process after changing environment configuration.
401 authentication failure The key is invalid, revoked, malformed, or from a different environment than expected. Check the secret value in the server’s secret manager and ensure it is not accidentally surrounded by literal quotes or whitespace. Rotate a key if it may have leaked.
400 invalid request A model does not accept a selected setting, a dimension is invalid, or the request field is misspelled. Compare the request with the current endpoint reference for that exact model. Verify size constraints, supported quality, output format, and transparency rules.
429 rate or quota error The project has reached a rate limit or lacks available quota. Reduce concurrency, use bounded backoff for rate limits, and check project billing and limits. Do not retry quota or billing failures indefinitely.
data[0] is undefined The response did not contain a generated image in the expected shape, or error handling was bypassed. Inspect the SDK error and response status. Guard the data access and fail explicitly rather than trying to decode a missing value.
Image file cannot be opened The base64 string was not decoded, the output was truncated, or file extension/content type does not match the requested format. Decode the returned data to bytes, confirm the request completed, and use the extension and MIME type matching the chosen output format.
Node reports an import or module error The project is using CommonJS while the sample uses ES modules. Use the .mjs extension as shown, or configure the project for ES modules. Alternatively adapt imports to the project’s module system without changing the SDK method or response handling.
Generation hangs or the client times out The operation takes longer than the application’s request timeout or the network connection is interrupted. Set a suitable timeout according to the current SDK reference, expose progress for long tasks, and use bounded recovery logic. Avoid starting an uncontrolled duplicate request after a client timeout.

10. Or skip the browser setup

This article generates images. If your application also needs a screenshot of a rendered website, ScreenshotNeo is a different tool: a one-call website screenshot API and MCP server, not an image-generation model. One GET request captures a URL as PNG, JPEG, WebP, or PDF. The API and SDK-style parameters are documented at ScreenshotNeo docs.

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

In production, check the response headers and content type before saving, and follow the API’s documented authentication and response behavior. ScreenshotNeo accepts cookie or consent banners as a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and responses identify verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000, and every feature is on every plan. Learn more at ScreenshotNeo. Sign up free for 1,000 screenshots a month, no card required.

11. FAQ

Can I call the image API from browser JavaScript?

Keep the API key in a server environment. Have the browser call your own authenticated endpoint, then return the image bytes or an application-managed asset reference.

Does the generation result contain a ready-to-use image URL?

The documented generation example returns base64 image data in the response. Decode it to bytes or use another response mode explicitly documented for your chosen endpoint.

Can I guarantee the same image from the same prompt?

Do not assume identical output on repeated requests. Store the output you intend to reuse and retain the relevant request metadata rather than regenerating it when a user revisits a page.

Which SDK method should I start with?

For a straightforward completed image, start with client.images.generate(). Use streaming only when incremental image events improve the application and you have implemented the current SDK’s event protocol.

Documentation to keep nearby: the Image Generation guide, the Images API reference, and the data controls page. Recheck accepted model names and settings at implementation time.