Skip to main content

Saving AI Generated Images to Imgwire

AI image-generation APIs often return temporary URLs or base64 image data. Save those results to Imgwire when your app needs durable hosting, transformations, presets, and CDN delivery.

This tutorial uses the OpenAI Node SDK for generation and @imgwire/node for storage.

Install packages

yarn add openai @imgwire/node

Set server-only environment variables:

OPENAI_API_KEY=...
IMGWIRE_API_KEY=sk_...

Do not put either key in browser code, mobile bundles, or public static files.

Generate and upload an image

Current OpenAI GPT image models return base64-encoded image data through the Images API. Convert that data to a Buffer, then upload the buffer to Imgwire.

import OpenAI from 'openai';
import { ImgwireClient } from '@imgwire/node';

const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY!,
});

const imgwire = new ImgwireClient({
apiKey: process.env.IMGWIRE_API_KEY!,
});

export async function generateAndSaveImage(prompt: string) {
const response = await openai.images.generate({
model: 'gpt-image-2',
prompt,
size: '1024x1024',
quality: 'medium',
output_format: 'png',
});

const generated = response.data?.[0];
if (!generated?.b64_json) {
throw new Error('OpenAI did not return image data.');
}

const imageBuffer = Buffer.from(generated.b64_json, 'base64');

const image = await imgwire.images.upload({
file: imageBuffer,
fileName: 'generated-image.png',
mimeType: 'image/png',
purpose: 'ai generated image',
customMetadata: {
source: 'openai',
model: 'gpt-image-2',
prompt,
},
});

return {
imageId: image.id,
previewUrl: image.url({
preset: 'medium',
format: 'auto',
quality: 'auto',
}),
};
}

The returned imageId is the durable application value. Store it with your generated image record, user project, document, or gallery item.

Use URL ingestion for temporary assets

Some AI providers return a temporary asset URL instead of base64 data. In that case, let Imgwire fetch the URL directly:

const image = await imgwire.images.uploadViaUrl({
url: temporaryAssetUrl,
purpose: 'ai generated image',
customMetadata: {
source: 'ai-provider',
workflow: 'prompt-to-image',
prompt,
},
});

const deliveryUrl = image.url({
width: 1200,
format: 'auto',
quality: 'auto',
});

Upload-by-URL is useful when the provider URL is short-lived and your app wants Imgwire to preserve the generated image before that URL expires.

Store useful metadata

Use customMetadata for details your app may need later:

customMetadata: {
source: 'openai',
model: 'gpt-image-2',
workflow: 'blog-hero-generator',
user_id: user.id,
}

Avoid storing secrets, private prompts, or sensitive user data in image metadata unless your application policy allows it.

Render generated images

Generated images usually need multiple render sizes. Store the ID, then generate variants for each surface:

const image = await imgwire.images.retrieve(imageId);

const cardUrl = image.url({
width: 640,
height: 360,
resizing_type: 'cover',
gravity: 'attention',
format: 'auto',
quality: 'auto',
});

const ogUrl = image.url({
width: 1200,
height: 630,
resizing_type: 'cover',
gravity: 'attention',
format: 'jpeg',
quality: 85,
});

Use format=auto for browser display and explicit format=jpeg when a downstream consumer requires a fixed content type.

Best practices

  • Generate and upload AI images from a backend, worker, or queue.
  • Store the Imgwire image ID with the generation record.
  • Capture source, model, and workflow metadata for debugging and moderation.
  • Use uploadViaUrl when a provider returns a temporary public URL.
  • Use format=auto&quality=auto for public previews and explicit transforms for social images.

Last updated at: May 8, 2026