Developer docs
FontPreview has two parts: drop-in widgets for your pages, and the render API they're built on. Widgets and the render API live at https://render.fontpreview.app; the account API used by the dashboard lives at https://api.fontpreview.app.
Quickstart
- 1Create an accountSign up and confirm your email address.
- 2Upload a fontIn Fonts → Upload, add TTF, OTF or WOFF files (up to 10 MB each). Each font gets an ID like
fnt_…. - 3Create a widget keyIn API Keys, create a widget key and add your site's origin, e.g.
https://shop.example.com. Copy the key when it's shown; it is displayed once. - 4Create a widget and embed itIn Widgets, create a widget, then copy its embed code. Paste your widget key into
data-keyand put the snippet on your page. - 5Check it rendersOpen the page on the origin you listed. If nothing appears, the browser console shows the error (most often an origin that isn't on the key).
<div id="font-tester"></div>
<script src="https://render.fontpreview.app/v1/tester.js"
data-key="fp_widget_…"
data-widget-id="wgt_…"
data-container="#font-tester"
defer></script>API keys
There are two kinds of key. Use the right one for where it runs.
| Key | Use it | Restrictions |
|---|---|---|
fp_widget_… | In public HTML: widget embeds and browser requests. | Works only from the origins you list on the key, and only for rendering. Requests without an Origin header are refused. |
fp_live_… | On your server only: render requests from backend code and minting signed URLs. | Full access to your account's rendering. Never put a live key in HTML, JavaScript bundles or a public repo. |
Keys are shown once when created and stored only as a hash, so we can't show them again. If you lose one, revoke it and create a new one. Send keys in the X-API-Key header (or the api_key query parameter for image URLs in HTML).
Origins are matched exactly on scheme, host and port: https://example.com does not cover https://www.example.com, so add both if you use both. Wildcards aren't supported. Allowed origins per key: Free 1, Starter 5, Pro unlimited, Enterprise unlimited.
Widgets
Each widget is a script at https://render.fontpreview.app/v1/<name>.js that renders inside a Shadow DOM, so your CSS and the widget's can't affect each other. Settings come from data-* attributes. With data-widget-id, the widget loads the configuration saved in the dashboard. Colours are 6-digit hex without #.
Script-tag embed
One widget per script tag, pointed at a container. Best for plain HTML and CMS embeds (see the quickstart snippet above).
Element embed
For single-page apps or several widgets on one page, put the settings on the container and load the bundle once. Call window.FontPreview.init() after adding containers dynamically; it only mounts containers that aren't mounted yet.
<div data-fp-widget="tester" data-key="fp_widget_…" data-font="fnt_a"></div>
<div data-fp-widget="tester" data-key="fp_widget_…" data-font="fnt_b"></div>
<script src="https://render.fontpreview.app/v1/tester.js" async></script>Attributes for every widget
| Attribute | Default | Meaning |
|---|---|---|
data-key | — | Required. A widget key (fp_widget_…) whose allowed origins include this page's origin. |
data-container | — | Script-tag embeds: CSS selector of the element to render into (required). |
data-fp-widget | — | Element embeds: the widget name (tester, badge, picker, …), set on the container itself. |
data-widget-id | — | Load the configuration saved in the dashboard. Inline attributes fill in anything it doesn't set. |
data-theme | light | light, dark, or auto (follows the visitor's colour scheme). |
data-color | 000000 | Text colour, 6-digit hex (a leading # is ignored). |
data-bg | ffffff | Background colour, 6-digit hex or transparent. |
data-debounce | 250 | Milliseconds to wait after typing before re-rendering. |
data-render-url | — | Override the render service URL. Script-tag embeds only; normally derived from the script's own src. |
Tester /v1/tester.js
Font: data-font (or set it in the dashboard).
| Attribute | Default | Meaning |
|---|---|---|
data-default-text | Type something... | Initial text. |
data-default-size | 48 | Initial size in px. |
data-default-color | 000000 | Text colour (the tester uses this instead of data-color). |
data-show-size-slider | true | Show the size slider. |
data-show-color-picker | false | Show a colour picker. |
data-min-size | 12 | Slider minimum. |
data-max-size | 200 | Slider maximum. |
data-max-length | 100 | Maximum characters a visitor can type. |
data-stroke-width | — | Stroke width (0.5–10) for single-line fonts. Defaults to the font's setting. |
Badge /v1/badge.js
Font: data-font (or set it in the dashboard).
| Attribute | Default | Meaning |
|---|---|---|
data-text | Preview | The sample text. |
data-size | 32 | Size in px. |
data-border-radius | 4 | Corner radius in px. |
Picker /v1/picker.js
Font: data-font-ids (or set it in the dashboard). data-font-ids is a comma- or space-separated list. data-font-names (comma list, same order) sets the labels.
| Attribute | Default | Meaning |
|---|---|---|
data-default-text | The quick brown fox | Sample text. |
data-layout | list | list or grid. |
data-columns | 2 | Grid columns, 1–6. |
data-size | 36 | Size in px. |
data-page-size | 10 | Fonts per page, 1–50. |
data-show-input | true | Let visitors edit the text. |
data-show-font-name | true | Label each sample. |
data-search | false | Show a filter box. |
data-selectable | false | Let visitors select fonts (fires fontpreview:select). |
data-multi-select | false | Allow more than one selection. |
Specimen /v1/specimen.js
Font: data-font (or set it in the dashboard).
| Attribute | Default | Meaning |
|---|---|---|
data-sections-order | metadata,tester,waterfall,paragraph,charset | Comma-separated section order. |
data-show-metadata | true | Include name, family, weight and style. |
data-show-tester | true | Include the type tester section. |
data-show-waterfall | true | Include the waterfall section. |
data-show-paragraph | true | Include the paragraph section. |
data-show-charset | true | Include the character set. |
data-waterfall-sizes | 72,48,36,24,18,14 | Sizes for the waterfall section. |
data-waterfall-text | The quick brown fox jumps over the lazy dog | Text for the waterfall section. |
data-paragraph-text | — | Text for the paragraph section. |
data-charset | latin-basic | latin-basic, latin-extended, cyrillic or custom. |
data-custom-chars | — | Characters to show when data-charset is custom. |
Waterfall /v1/waterfall.js
Font: data-font (or set it in the dashboard).
| Attribute | Default | Meaning |
|---|---|---|
data-text | Hamburgevons | Sample text. |
data-sizes | 72,60,48,36,24,18,14,12 | Comma-separated sizes in px (8–400, up to 20). |
data-show-size-labels | true | Label each row with its size. |
data-label-position | left | left or right. |
data-show-input | false | Let visitors edit the text. |
Paragraph /v1/paragraph.js
Font: data-heading-font (or set it in the dashboard). Add data-body-font for a second font; it defaults to the heading font.
| Attribute | Default | Meaning |
|---|---|---|
data-heading-text | The Art of Typography | Heading text. |
data-body-text | — | Body text. |
data-heading-size | 48 | Heading size in px. |
data-body-size | 16 | Body size in px. |
data-line-height | 1.5 | Body line height. |
data-editable | true | Let visitors edit the text. |
data-show-font-names | true | Label the fonts. |
data-heading-font-name | Heading | Label for the heading font. |
data-body-font-name | Body | Label for the body font. |
Customizer /v1/customizer.js
Font: data-font-ids (or set it in the dashboard). Also requires data-bg-image (https URL of the product photo) and data-text-area (x,y,width,height in the photo's pixels).
| Attribute | Default | Meaning |
|---|---|---|
data-font-names | — | Comma list of labels for the font menu, same order as data-font-ids. |
data-default-font-id | — | Font selected first. Defaults to the first in the list. |
data-default-text | Your text here | Initial text. |
data-default-size | 36 | Initial size in px. |
data-default-color | 000000 | Initial text colour. |
data-max-length | 50 | Maximum characters. |
data-show-font-selector | true | Show the font menu. |
data-show-color-picker | true | Show the colour picker. |
data-show-size-slider | true | Show the size slider. |
data-cart-integration | — | shopify, woocommerce or custom: adds an Add to cart button that fires fontpreview:add-to-cart. |
Gallery /v1/gallery.js
Font: data-family-id (or set it in the dashboard). data-family-id is the family name as shown in the dashboard. Or pass data-font-ids (and optional data-font-names) instead.
| Attribute | Default | Meaning |
|---|---|---|
data-default-text | Typography | Sample text. |
data-layout | grid | grid or list. |
data-columns | 2 | Grid columns, 1–6. |
data-size | 36 | Size in px. |
data-sort | weight | weight or name. |
data-show-weight-labels | true | Label weights. |
data-show-style-labels | true | Label styles. |
data-show-input | true | Let visitors edit the text. |
Widgets dispatch DOM events on the container element (bubbling): fontpreview:select from the picker and fontpreview:add-to-cart from the customizer.
Render API
GET https://render.fontpreview.app/v1/render/{fontId}?text=…Returns image/png or image/webp. Responses carry Cache-Control: public, max-age=3600 and X-Render-Cache: HIT|MISS. Only misses count toward your monthly render allowance. Your watermark is applied server-side according to your plan and settings; it can't be changed with a query parameter.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
text | string, 1–500 chars | — | Required. The text to set. A newline (%0A) starts a new line. |
size | integer 8–400 | 48 | Font size in CSS pixels. |
color | hex, 6 digits, no # | 000000 | Text colour. |
bg | hex or transparent | transparent | Background colour. |
width | integer 1–4000 | — | Canvas width in pixels. Defaults to the text's width. |
height | integer 1–4000 | — | Content height in pixels (the watermark band is added on top of this). Defaults to the text's height. |
padding | integer 0–200 | 16 | Space around the text in pixels. |
align | left | center | right | left | Horizontal alignment inside the canvas. |
format | png | webp | png | Image format. WebP is lossless. |
quality | integer 1–100 | 90 | Reserved for lossy output; has no effect on PNG or WebP today. |
dpr | integer 1–3 | 1 | Device pixel ratio. 2 renders at double resolution for retina screens. |
line_height | number 1–3 | 1.3 | Line spacing for multi-line text, as a multiple of the size. |
stroke_width | number 0.5–10 | — | Stroke width for single-line (engraving) fonts. Defaults to the font's setting, or 1.5. |
features | comma-separated tags | — | OpenType features to switch on, e.g. smcp,ss01,liga. Unknown tags are ignored. |
curl "https://render.fontpreview.app/v1/render/fnt_…?text=Hello%20world&size=72&color=1c2140&dpr=2" \
-H "X-API-Key: fp_live_…" \
-o hello.pngSigned URLs
To put a render in an <img> tag without exposing any key, mint a short-lived signed URL from your server with a live key. The signature covers the font and every parameter, so the URL can't be edited to render different text.
curl -X POST "https://api.fontpreview.app/render-tokens" \
-H "X-API-Key: fp_live_…" -H "Content-Type: application/json" \
-d '{"fontId":"fnt_…","text":"Hello","size":64,"expiresIn":300}'
# → {"data":{"url":"https://render.fontpreview.app/v1/render/fnt_…?…&sig=…","exp":1767225600}}The body takes the same options as the render API in camelCase (lineHeight, strokeWidth) plus expiresIn (30–3600 seconds, default 300). Widget keys can't mint signed URLs.
Errors
Errors are JSON with a stable code:
{ "error": { "code": "RATE_LIMITED", "message": "…", "details": { "retryAfter": 12 } } }| Status | Code | When |
|---|---|---|
| 400 | VALIDATION_FAILED | A parameter is missing or out of range, or the final image would exceed 2048×2048 device pixels. |
| 401 | UNAUTHORIZED | No API key, or the key is unknown or revoked. |
| 401 | SIGNATURE_INVALID | A signed URL was altered or signed with the wrong secret. |
| 401 | SIGNATURE_EXPIRED | A signed URL is past its exp time. |
| 403 | FORBIDDEN | A widget key was used from an origin that isn't on its list, or without an Origin header. |
| 404 | NOT_FOUND | The font doesn't exist or belongs to another account. |
| 422 | RENDER_FAILED | The font couldn't render this text. |
| 422 | FONT_UNSUPPORTED | The stored font file can't be rendered (for example a legacy WOFF2 upload). |
| 429 | RATE_LIMITED | Too many requests this minute. Wait for Retry-After seconds. |
| 429 | QUOTA_EXCEEDED | The monthly render allowance is used up. |
| 5xx | SERVER_ERROR / RENDER_TIMEOUT | Temporary failure. Retry with backoff. |
Rate limits
Requests are limited per minute by plan. Every response carries X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds); a 429 also carries Retry-After.
| Plan | Requests / minute | Renders / month |
|---|---|---|
| Free | 10 | 5,000 |
| Starter | 100 | 100,000 |
| Pro | 1,000 | 1,000,000 |
| Enterprise | 10,000 | 100,000,000 |