Web Widgets

Web widgets allow you to embed Enconvert's URL and file conversion capabilities directly into any website. Visitors can convert URLs to PDFs, capture screenshots, or convert uploaded files without leaving your page. No API key is exposed in the frontend code.


Overview

Widgets are configured through the Enconvert dashboard and embedded as iframes via a lightweight script tag. Each widget is tied to a single conversion endpoint and a list of allowed domains. Authentication is handled automatically using Cloudflare Turnstile challenges, short-lived JWT tokens, and automatic token refresh.

Supported conversion endpoints:

Any Enconvert conversion endpoint can be used with widgets, including:


How Widgets Work

Setup

  1. Go to your Enconvert Dashboard > Widgets and click Create Widget.
  2. Select the conversion endpoint (e.g., /v1/convert/url-to-pdf) and specify the domains where the widget will be embedded. Wildcard subdomains are supported (e.g., *.example.com).
  3. An internal public API key is automatically created for the widget, restricted to the selected endpoint and allowed domains. This key is never exposed.

Embedding

Add the embed script to your website:

<script src="https://enconvert.com/embed.js" data-widget-id="your-widget-id"></script>

The script creates a sandboxed iframe that loads the Enconvert widget. No API key appears in the embed code.

Runtime Flow

  1. Widget loads in the iframe and fetches its configuration from GET /v1/widget/{widget_id}/config.
  2. Domain validation -- the widget verifies the parent page's origin matches the allowed domains list. Supports exact domains and wildcard subdomain patterns (*.example.com).
  3. User submits a URL or file -- the widget requests an invisible Turnstile challenge token.
  4. Token exchange -- the widget sends the Turnstile token to POST /v1/widget/{widget_id}/token and receives a JWT (1-hour expiry) plus a refresh token cookie (7-day expiry).
  5. Conversion -- the widget calls the conversion endpoint with the JWT.
  6. Result -- the API returns a JSON response with a presigned_url. The widget displays a download link.
  7. Timeout recovery -- if the conversion exceeds reverse-proxy timeout limits, the widget polls GET /v1/convert/status/{job_id} using the pre-generated job ID.

Automatic Token Refresh

The widget never stops working due to expired authentication:

  • On the initial conversion, the API issues both a JWT (1-hour expiry) and a refresh token (7-day expiry, httpOnly cookie).
  • On subsequent conversions, the widget first attempts to refresh the JWT via POST /v1/widget/{widget_id}/refresh using the refresh token cookie -- no Turnstile challenge required.
  • If the refresh token itself has expired (after 7 days of inactivity), the widget falls back to a new Turnstile challenge.
  • The refresh token is rotated on every refresh -- each refresh issues a new 7-day cookie.

This means a widget visitor who converts every few days will never see a Turnstile challenge after the first one.


Widget Endpoints

Configuration

Retrieves the configuration for a specific widget. No authentication required.

GET /v1/widget/{widget_id}/config

Response:

{
    "endpoint": "/v1/convert/url-to-pdf",
    "input_type": "url",
    "allowed_domains": ["https://example.com", "*.example.com"],
    "turnstile_site_key": "1x00000000000000000000AA",
    "widget_branding": true
}
Field Description
endpoint The conversion endpoint this widget is configured to use.
input_type "url" for URL-based endpoints, "file" for file upload endpoints.
allowed_domains Domains authorized to embed this widget. Supports wildcards.
turnstile_site_key Cloudflare Turnstile site key for bot verification.
widget_branding Whether the "Powered by Enconvert" badge is displayed. Determined by the subscription plan.

Token Exchange

Exchanges a Turnstile challenge token for a JWT. Sets a refresh token cookie.

POST /v1/widget/{widget_id}/token
X-Parent-Origin: https://your-website.com
Content-Type: application/json

{
    "turnstile_token": "cloudflare-challenge-response-token"
}

Response:

{
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "token_type": "Bearer",
    "expires_in": 3600
}

Also sets an httpOnly refresh_token cookie (7-day expiry, Secure, SameSite=none).

Token Refresh

Refreshes an expired JWT using the httpOnly refresh token cookie. No Turnstile challenge required.

POST /v1/widget/{widget_id}/refresh
X-Parent-Origin: https://your-website.com

No request body needed -- the refresh token is read from the cookie automatically.

Response:

{
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "token_type": "Bearer",
    "expires_in": 3600
}

The refresh token cookie is rotated on each refresh (new 7-day cookie issued).

Error responses: - 401 -- no refresh token cookie or refresh token expired - 403 -- refresh token does not match the widget's project, or domain not authorized - 404 -- widget not found or deactivated


Conversion Response

Both URL-based and file-based widget conversions return a consistent JSON response with a presigned download URL:

{
    "presigned_url": "https://spaces.example.com/...",
    "object_key": "env/files/{project_id}/url-to-pdf/example_20260405_123456789.pdf",
    "filename": "example_20260405_123456789.pdf",
    "file_size": 123456,
    "conversion_time_seconds": 8.5,
    "job_id": "client-generated-uuid"
}

The widget uses the presigned_url to display a download link. Presigned URLs expire after 15 minutes.

Widget conversion restrictions: - Single URL / single file only - Synchronous mode only (no async or batch) - No webhook callbacks or notification emails - Endpoint restricted to the one configured for the widget


Widget Branding

Plans that include widget branding display a small "Powered by Enconvert" badge at the bottom of the widget. This is controlled by the widget_branding field on the subscription plan:

Plan Branding
Free / Starter Displayed
Pro / Enterprise Hidden

The branding badge links to https://enconvert.com and is styled to be unobtrusive -- small text below the widget form with reduced opacity.

To remove branding, upgrade to a Pro or Enterprise plan.


Widget Management

Widgets are managed through the Enconvert dashboard or the backend API:

Operation Endpoint Description
Create POST /api/widgets Creates a widget and auto-generates an internal public API key.
List GET /api/widgets?project_id={id} Lists all active widgets for a project.
Get GET /api/widgets/{id} Retrieves a single widget's details.
Update PATCH /api/widgets/{id} Updates widget name, endpoint, or API key.
Delete DELETE /api/widgets/{id} Soft-deletes the widget (sets active=false).

Embed Code Reference

Standard HTML

<script src="https://enconvert.com/embed.js" data-widget-id="your-widget-id"></script>

The script: - Creates a sandboxed iframe (allow-scripts allow-same-origin allow-forms allow-popups) - Sets width: 100%, initial height 400px, no border - Enables clipboard-write permission - Uses lazy loading - Listens for Enconvert:resize messages to auto-adjust height

WordPress Shortcode

If you use the Enconvert WordPress plugin, embed widgets using the shortcode:

[enconvert_widget id="your-widget-id"]

Style Customization

Customize the widget appearance via query parameters on the embed script URL or the iframe source:

Parameter CSS Variable Description
bg --w-bg Widget background color
text --w-text Text color
btn-bg --w-btn-bg Button background color
btn-text --w-btn-text Button text color
border --w-border Border color
radius --w-radius Border radius
input-bg --w-input-bg Input field background
result-bg --w-result-bg Result area background
error --w-error Error text color
font --w-font Font family
padding --w-padding Widget padding
max-width --w-max-width Maximum widget width

Iframe Communication

The widget communicates with the parent page via postMessage. Listen for these events on the parent page:

Event Type Data Description
Enconvert:ready -- Widget has loaded and is ready.
Enconvert:resize { height: number } Widget content height changed. Use to resize the iframe.
Enconvert:conversion:complete { url: string, filename?: string } Conversion completed. url is the presigned download URL.
Enconvert:conversion:error { error: string } Conversion failed.

Example: Listening for Events

window.addEventListener("message", function(e) {
    if (!e.data || !e.data.type) return;

    if (e.data.type === "Enconvert:conversion:complete") {
        console.log("Conversion done:", e.data.data.url);
    }

    if (e.data.type === "Enconvert:conversion:error") {
        console.error("Conversion failed:", e.data.data.error);
    }
});

Security

Layer Protection
Domain whitelisting Widget only functions on listed domains. Supports exact matches and wildcard subdomains. Server-side validation on token issuance.
Turnstile verification Every initial token request requires a valid Cloudflare Turnstile challenge response.
Endpoint restriction Each widget is locked to a single conversion endpoint via allowed_endpoints in the JWT.
Token expiry JWT expires after 1 hour. Refresh token expires after 7 days. Both are rotated on refresh.
Refresh token security httpOnly cookie with Secure and SameSite=none -- inaccessible to JavaScript, only sent over HTTPS.
CORS protection API gateway validates the widget iframe origin on every request.
CSP frame-ancestors Widget config and token endpoints set frame-ancestors headers restricting which domains can embed the iframe.
No exposed keys Embed code contains only the widget ID. The internal API key is never visible.