Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Pass the color as a runtime style value on the text layer or template modification instead of baking colored text into a source bitmap. In Cloudinary, use font_color with the text API or the co color qualifier on an l_text overlay. In Bannerbear, send a hex value in a template modification’s color or background field. This keeps one template reusable while each record receives its own color.
Choose the right runtime model
There are two practical patterns:
- Transformation-based generation: Cloudinary builds an image from a URL or SDK transformation. You control text, font, placement, and color in the request.
- Template-based generation: Bannerbear starts with a managed design and applies per-request modifications to named layers.
In either model, store a validated color value with each record, then pass it when rendering. Do not create a separate flattened image for every color unless you specifically need a fixed, uneditable asset.
Cloudinary: generate text with a color parameter
Cloudinary’s Upload API text endpoint is POST /image/text. Its font_color option controls the generated text color, along with font and style settings. The current Cloudinary documentation was updated June 22, 2026; consult the Upload API reference for the request schema.
Send a text-generation request
A conceptual JSON request looks like this (authenticate using the method required by your Cloudinary account):
{
"text": "Order 1842",
"font_family": "Arial",
"font_size": 64,
"font_color": "#FFFFFF",
"font_weight": "bold"
}
The important field is font_color. Keep the value in a canonical form such as #FFFFFF, then reject malformed input before it reaches the API.
#1 Best Overall
Use a text overlay on an existing image
For an image transformation, Cloudinary uses a text layer (l_text) and a color qualifier (co). This example places bold yellow Times text near the bottom:
.../co_rgb:FFFF00,l_text:Times_90_bold:Style/fl_layer_apply,g_south,y_20/...
The co_rgb:FFFF00 qualifier supplies the color; l_text:Times_90_bold:Style defines the text layer; and fl_layer_apply,g_south,y_20 applies it at the bottom with a 20-pixel offset. Cloudinary documents the color qualifier and text-layer syntax in its layers documentation.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Supported color forms
Cloudinary accepts named colors, three- or six-digit RGB hex values, and four- or eight-digit RGBA hex values. If you omit the color property, the default is black. In URL transformations, encode the color in the qualifier syntax rather than sending a CSS declaration.
Rank #2
| Input | Use | Example |
|---|---|---|
| Named color | Simple, readable styles | black |
| RGB hex | Opaque color | co_rgb:FFFF00 |
| RGBA hex | Color plus alpha channel | co_rgb:FF000080 |
| Omitted | Cloudinary default | Black |
Vary color by record with variables
Cloudinary user-defined variables can hold a color and be referenced by the text-overlay style. Define one transformation template, assign a different color for each record, and generate each URL from the same structure. This avoids duplicating templates for every brand, status, or campaign color. See the variable and conditional transformation documentation for variable syntax and evaluation rules.
// Pseudocode: validate first, then bind the value to your transformation
const color = validateHex(record.textColor); // e.g. "#1E40AF"
const imageUrl = buildCloudinaryUrl({
text: record.title,
textColor: color
});
When constructing a URL yourself, follow Cloudinary’s escaping rules for text, font names, and special characters. SDKs provide equivalent mapped options such as font_color: "black" or an RGB value.
Bannerbear: change a template layer per request
Bannerbear renders JPG or PNG output from a template and a list of modifications. A modification can replace text and set a layer’s color or background with a hex value such as #FF0000. The approach suits teams that name design layers once and fill them from application data.
Modification example
{
"template": "TEMPLATE_UID",
"modifications": [
{
"name": "headline",
"text": "System status: OK",
"color": "#16A34A"
},
{
"name": "headline_container",
"background": "#ECFDF5"
}
]
}
Use the exact layer names from your Bannerbear template and send the request through its authenticated API. Bannerbear’s technical guidance says color can be changed for primary text, secondary text, and a text container; #FFD700 is one documented example. See the Bannerbear color guide and API documentation.
When to choose Bannerbear
- Use it when non-developers maintain a reusable visual template.
- Use named layers when each record needs predictable text and background changes.
- Keep color in the modification payload so one template serves multiple brands or statuses.
Cloudinary and Bannerbear compared
| Question | Cloudinary | Bannerbear |
|---|---|---|
| Primary workflow | URL or SDK transformations and text generation | Managed template plus modifications |
| Color field | font_color in text API; co in overlays |
color and background in modifications |
| Per-record color | Variables can inject a color into one transformation template | Send a color with each layer modification |
| RGBA/opacity | Three- and six-digit RGB plus four- and eight-digit RGBA are supported | Use the documented hex fields; the cited guidance does not establish an RGBA range |
| Typography and placement | Font, size, style, layer placement, and transformation controls | Defined primarily by the template and its named layers |
Validate and select colors safely
Accept only the formats you intend to support
A strict validator prevents malformed URLs, accidental transparent text, and unreadable output. For opaque six-digit hex values:
Rank #3
function validateHex(value) {
if (!/^#[0-9A-Fa-f]{6}$/.test(value)) {
throw new Error('Color must be a six-digit hex value such as #2563EB');
}
return value.toUpperCase();
}
If your provider and design require alpha, explicitly permit four- or eight-digit values and document what the alpha channel means. Do not silently convert user-entered CSS names or shorthand unless your API path supports them.
Check contrast before rendering
Compare the requested foreground with its background. A valid color can still make text unreadable. For accessibility-sensitive interfaces, calculate relative luminance and enforce your project’s contrast target before queueing the image. Also test long strings, all-caps labels, and fonts with thin strokes; color alone cannot fix insufficient size or weight.
Recommended Free Tools
Keep data and design separate
Store fields such as text, textColor, and backgroundColor separately from the template identifier. This lets you change the design without migrating every record and lets you audit which data produced an image.
Rendering reliability and delivery
- Cache by complete inputs: include the text, color, font, template version, and background in your cache key. Otherwise a color change may return an older image.
- Encode dynamic text: punctuation, spaces, slashes, and non-Latin characters need provider-specific escaping.
- Expect asynchronous work: template services may return a job or URL rather than bytes immediately. Persist the job identifier and retry status checks with backoff.
- Keep the original parameters: record the exact color and template version alongside the delivered asset for reproducibility.
- Test transparent backgrounds: RGBA text can look correct on one preview and disappear on another background.
Troubleshooting common color failures
The text is black
In Cloudinary, an omitted color defaults to black. Confirm that font_color is present in a text-generation request or that the overlay URL contains the co qualifier. In Bannerbear, verify that the modification targets the text layer’s exact name and uses color, not a field your template does not recognize.
The request is rejected
Check authentication, required template or public-ID fields, and the provider’s encoding rules. Validate the color before constructing the request; a stray space, missing #, or unsupported alpha format can invalidate it.
The color appears unchanged
Inspect the final URL or JSON sent over the wire, not only the object before serialization. A cache key that excludes color can serve a previous render. Purge or version the cached transformation after changing the style.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesThe text is hard to read
Measure contrast against the actual background, then adjust the color, weight, size, or a container background. Do not assume a brand color is legible on every image.
Characters or line breaks are wrong
Escape the text according to the provider’s URL rules or SDK, confirm the selected font contains the required glyphs, and reserve enough width for the longest record. A color fix cannot correct clipping caused by layout.
Or skip the browser setup
If your goal is to capture the final rendered page or image rather than build a graphics pipeline, ScreenshotNeo makes a clean screenshot with one request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status.
Use the API directly (see the ScreenshotNeo documentation):
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.
Frequently Asked Questions
Can I use a CSS color name instead of hex?
Cloudinary documents named colors as supported, while Bannerbear examples use hex values. Follow the format accepted by the specific endpoint you call.
Do I need a new template for every text color?
No. Pass the color at render time: Cloudinary variables can feed one transformation template, and Bannerbear modifications can set each layer’s color.
Why does changing the color not change the image URL?
If your cache key or transformation URL omits the color parameter, the delivery layer may reuse an older result. Include every visual input in the key.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

