New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

@copperline/rendex

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@copperline/rendex

Official TypeScript SDK for Rendex — render HTML or Markdown to images, generate PDFs, capture screenshots, and monitor pages for changes with Rendex Watch

latest
npmnpm
Version
1.8.1
Version published
Weekly downloads
0
-100%
Maintainers
1
Weekly downloads
 
Created
Source

@copperline/rendex

Official TypeScript SDK for Rendex — the HTML-to-image, PDF, and screenshot rendering API. Turn raw HTML, Markdown, or any webpage into an image or PDF with a single function call.

  • Zero runtime dependencies (uses native fetch)
  • Full TypeScript types with IntelliSense
  • Works in Node.js 18+, Deno, Bun, and browsers
  • Typed error handling with API error codes

Install

npm install @copperline/rendex
# or
pnpm add @copperline/rendex
# or
bun add @copperline/rendex

Quick Start

import { Rendex } from "@copperline/rendex";

const rendex = new Rendex("your-api-key");

// Render raw HTML straight to a PNG
const { image, metadata } = await rendex.renderHtml("<h1>Hello, world</h1>");

// Or render Markdown (converted to HTML server-side)
const md = await rendex.renderMarkdown("# Hello, world");

// Or capture a live URL
const shot = await rendex.screenshot({
  url: "https://example.com",
  format: "png",
  fullPage: true,
});

// Write to file (Node.js)
import { writeFile } from "node:fs/promises";
await writeFile("screenshot.png", image);

console.log(`${metadata.bytesSize} bytes, loaded in ${metadata.loadTimeMs}ms`);

API Reference

new Rendex(apiKey, config?)

Create a new Rendex client.

const rendex = new Rendex("your-api-key", {
  baseUrl: "https://api.rendex.dev", // optional, default
});
ParameterTypeDescription
apiKeystringYour Rendex API key. Get one at rendex.dev
config.baseUrlstringOverride the API base URL
config.fetchtypeof fetchCustom fetch implementation (for testing)

rendex.screenshot(options)

Capture a screenshot and return the binary image with metadata.

const { image, metadata } = await rendex.screenshot({
  url: "https://example.com",
  format: "webp",
  width: 1920,
  height: 1080,
  darkMode: true,
});

Returns Promise<ScreenshotResult>:

  • imageUint8Array of the captured image
  • metadataScreenshotMetadata with URL, dimensions, format, bytes, load time, quality signal

rendex.renderHtml(html, options?)

Render raw HTML straight to a PNG (or any format) and return the binary image with metadata. Convenience wrapper over screenshot({ html }).

const { image, metadata } = await rendex.renderHtml("<h1>Hello, world</h1>", {
  format: "png",
  width: 1200,
});

Returns Promise<ScreenshotResult> — same shape as screenshot().

rendex.renderHtmlJson(html, options?)

Render raw HTML and return JSON with a base64-encoded image. Convenience wrapper over screenshotJson({ html }).

const result = await rendex.renderHtmlJson("<h1>Hello, world</h1>");
console.log(result.data.bytesSize);

Returns Promise<ScreenshotJsonResponse> — same shape as screenshotJson().

rendex.renderMarkdown(markdown, options?)

Render Markdown straight to a PNG (or any format) and return the binary image with metadata. The Markdown is converted to HTML server-side. Convenience wrapper over screenshot({ markdown }).

const { image, metadata } = await rendex.renderMarkdown("# Hello, world", {
  format: "png",
  width: 1200,
});

Returns Promise<ScreenshotResult> — same shape as screenshot().

rendex.renderMarkdownJson(markdown, options?)

Render Markdown and return JSON with a base64-encoded image. The Markdown is converted to HTML server-side. Convenience wrapper over screenshotJson({ markdown }).

const result = await rendex.renderMarkdownJson("# Hello, world");
console.log(result.data.bytesSize);

Returns Promise<ScreenshotJsonResponse> — same shape as screenshotJson().

HTML and Markdown rendering is POST-only and accepts up to 5MB. It is not available via screenshotUrl() (the GET endpoint can't carry a body). Provide exactly one of url, html, or markdown.

Mustache data templating

Pass a data object alongside html or markdown to render logic-less Mustache templates before capture. The server substitutes the template variables and then renders the resulting HTML.

// Markdown invoice with a line-item loop
const template = `
# Invoice {{number}}

**Customer:** {{customer}}

| Item | Qty | Price |
|------|-----|-------|
{{#items}}
| {{description}} | {{qty}} | ${{price}} |
{{/items}}

**Total: ${{total}}**
`;

const { image } = await rendex.renderMarkdown(template, {
  data: {
    number: "INV-2026-042",
    customer: "Acme Corp",
    items: [
      { description: "Rendex Pro (monthly)", qty: 1, price: "49.00" },
      { description: "Extra render credits", qty: 500, price: "5.00" },
    ],
    total: "54.00",
  },
  format: "pdf",
});

Template syntax:

SyntaxDescription
{{var}}HTML-escaped substitution
{{{var}}}Raw (unescaped) substitution
{{#items}}…{{/items}}Section — iterates an array or renders a truthy block
{{^x}}…{{/x}}Inverted section — renders when x is falsy / empty
{{a.b}}Nested property access

data is only valid with html or markdown. Passing it alongside url returns a 400 error. The data object is capped at 256KB serialized.

rendex.screenshotJson(options)

Capture a screenshot and return JSON with a base64-encoded image.

const result = await rendex.screenshotJson({
  url: "https://example.com",
});

console.log(result.data.image);          // base64 string
console.log(result.data.bytesSize);      // 45823
console.log(result.meta.usage?.remaining); // 499

Returns Promise<ScreenshotJsonResponse> with data (image + metadata) and meta (request ID, usage).

rendex.screenshotUrl(options)

Generate a GET URL for embedding. No network call — pure URL builder.

const url = rendex.screenshotUrl({
  url: "https://example.com",
  format: "png",
  width: 1200,
});
// Use in <img> tags, OpenGraph, etc.

Note: The API key is included in the URL. Use server-side only.

Returns string — a complete URL to the screenshot endpoint.

Screenshot Options

All options except url are optional:

OptionTypeDefaultDescription
urlstringrequiredThe webpage URL to capture
format"png" | "jpeg" | "webp" | "pdf""png"Output format
widthnumber1280Viewport width (320–3840)
heightnumber800Viewport height (240–2160)
fullPagebooleanfalseCapture the full scrollable page
qualitynumber80JPEG/WebP quality (1–100, default 80)
delaynumber0Delay before capture in ms (0–10000)
darkModebooleanfalseEmulate dark mode
deviceScaleFactornumber2Device pixel ratio (1–3). 2× Retina by default
blockAdsbooleantrueBlock ads and trackers
blockResourceTypesstring[]Block: "font", "image", "media", "stylesheet", "other"
timeoutnumber30Page load timeout in seconds (5–60)
waitUntilstring"networkidle2"Wait strategy: "load", "domcontentloaded", "networkidle0", "networkidle2"
waitForSelectorstringCSS selector to wait for before capture
bestAttemptbooleantrueReturn best-effort screenshot on timeout
selectorstringCapture a specific element by CSS selector

Rendex Watch

Monitor a URL on a schedule and get alerted when it changes — real-Chrome visual diff (with a highlighted overlay), an extracted-text diff, or both. One rdx_ key, your shared credit pool.

// Create a watch (an active watch captures its baseline immediately — 1 credit)
const watch = await rendex.createWatch({
  url: "https://example.com/pricing",
  diffMode: "visual",          // "visual" | "text" | "both"
  intervalMinutes: 1440,       // your plan's floor is the minimum (Free 1440 / Starter 180 / Pro 30 / Ent 5)
  webhookUrl: "https://hooks.example.com/rendex", // Starter+; HMAC-signed
  notifyEmail: "you@example.com",                 // any plan; must be your account email
});

// Dry-run a config BEFORE saving — what we'd capture + is the page reachable
const test = await rendex.testWatch({ url: "https://example.com", selector: "#price" });
if (test.reachable) console.log(test.screenshotUrl);

await rendex.listWatches({ status: "active" });   // { items, nextCursor }
await rendex.getWatch(watch.id);
await rendex.runWatch(watch.id);                   // run a check now → { runId }
const { items } = await rendex.listWatchRuns(watch.id, { limit: 10 });
await rendex.updateWatch(watch.id, { paused: true });   // pause; { paused: false } resumes
await rendex.deleteWatch(watch.id);
MethodEndpointReturns
createWatch(options)POST /v1/watchesWatch
listWatches(query?)GET /v1/watches{ items: Watch[]; nextCursor }
getWatch(id)GET /v1/watches/:idWatch
updateWatch(id, patch)PATCH /v1/watches/:idWatch
deleteWatch(id)DELETE /v1/watches/:idvoid
runWatch(id)POST /v1/watches/:id/run{ runId, watchId, status }
listWatchRuns(id, query?)GET /v1/watches/:id/runs{ items: WatchRun[]; nextCursor }
testWatch(options)POST /v1/watches/testWatchTestResult

Verifying Watch webhooks

When a watched page changes Rendex POSTs an HMAC-signed watch.changed (or watch.recovered / watch.error) event to your webhookUrl. Verify it with the raw request body:

import { verifyWebhook, type RendexWebhookPayload } from "@copperline/rendex";

// rawBody is the unparsed request body string
const ok = await verifyWebhook({
  payload: rawBody,
  signature: req.headers["x-rendex-signature"],
  timestamp: req.headers["x-rendex-timestamp"],
  secret: process.env.WEBHOOK_SIGNING_SECRET,
});
if (!ok) return res.status(400).end();

const event = JSON.parse(rawBody) as RendexWebhookPayload;
if (event.event === "watch.changed") {
  console.log(event.url, event.diffScore, event.diffOverlayUrl);
}

A watch.changed payload carries the same change fields as a WatchRun: diffScore, diffPixels, beforeUrl, afterUrl, diffOverlayUrl, cropUrl (a tight crop of just the changed region), changedRegion (its normalized 0–1 coordinates), and summary (a one-line plain-English "what changed" sentence — on every plan).

Error Handling

import { Rendex, RendexApiError, RendexNetworkError } from "@copperline/rendex";

const rendex = new Rendex("your-api-key");

try {
  await rendex.screenshot({ url: "https://example.com" });
} catch (error) {
  if (error instanceof RendexApiError) {
    // API returned an error
    console.error(error.errorCode);  // "RATE_LIMITED", "VALIDATION_ERROR", etc.
    console.error(error.statusCode); // 429, 400, etc.
    console.error(error.requestId);  // For debugging with Rendex support
    console.error(error.details);    // Validation details (if any)
  } else if (error instanceof RendexNetworkError) {
    // Network failure (DNS, timeout, connection refused)
    console.error("Network error:", error.message);
  }
}

Error Codes

CodeHTTP StatusDescription
VALIDATION_ERROR400Invalid request parameters
INVALID_URL400URL failed SSRF validation
TIMEOUT408Page took too long to load
CAPTURE_FAILED500Browser rendering error
RATE_LIMITED429Rate limit exceeded
USAGE_EXCEEDED429Monthly credit limit reached
MISSING_API_KEY401No API key provided
INVALID_API_KEY401API key verification failed

License

MIT - Copperline Labs LLC

Keywords

rendex

FAQs

Package last updated on 20 Jul 2026

Related posts