
Security News
GitHub Actions Adds cache-mode to Limit Cache Poisoning Risk
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.
@copperline/rendex
Advanced tools
Official TypeScript SDK for Rendex β render HTML or Markdown to images, generate PDFs, and capture screenshots
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.
fetch)npm install @copperline/rendex
# or
pnpm add @copperline/rendex
# or
bun add @copperline/rendex
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`);
new Rendex(apiKey, config?)Create a new Rendex client.
const rendex = new Rendex("your-api-key", {
baseUrl: "https://api.rendex.dev", // optional, default
});
| Parameter | Type | Description |
|---|---|---|
apiKey | string | Your Rendex API key. Get one at rendex.dev |
config.baseUrl | string | Override the API base URL |
config.fetch | typeof fetch | Custom 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>:
image β Uint8Array of the captured imagemetadata β ScreenshotMetadata with URL, dimensions, format, bytes, load time, quality signalrendex.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 ofurl,html, ormarkdown.
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:
| Syntax | Description |
|---|---|
{{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.
All options except url are optional:
| Option | Type | Default | Description |
|---|---|---|---|
url | string | required | The webpage URL to capture |
format | "png" | "jpeg" | "webp" | "pdf" | "png" | Output format |
width | number | 1280 | Viewport width (320β3840) |
height | number | 800 | Viewport height (240β2160) |
fullPage | boolean | false | Capture the full scrollable page |
quality | number | 80 | JPEG/WebP quality (1β100, default 80) |
delay | number | 0 | Delay before capture in ms (0β10000) |
darkMode | boolean | false | Emulate dark mode |
deviceScaleFactor | number | 2 | Device pixel ratio (1β3). 2Γ Retina by default |
blockAds | boolean | true | Block ads and trackers |
blockResourceTypes | string[] | β | Block: "font", "image", "media", "stylesheet", "other" |
timeout | number | 30 | Page load timeout in seconds (5β60) |
waitUntil | string | "networkidle2" | Wait strategy: "load", "domcontentloaded", "networkidle0", "networkidle2" |
waitForSelector | string | β | CSS selector to wait for before capture |
bestAttempt | boolean | true | Return best-effort screenshot on timeout |
selector | string | β | Capture a specific element by CSS selector |
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);
}
}
| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR | 400 | Invalid request parameters |
INVALID_URL | 400 | URL failed SSRF validation |
TIMEOUT | 408 | Page took too long to load |
CAPTURE_FAILED | 500 | Browser rendering error |
RATE_LIMITED | 429 | Rate limit exceeded |
USAGE_EXCEEDED | 429 | Monthly credit limit reached |
MISSING_API_KEY | 401 | No API key provided |
INVALID_API_KEY | 401 | API key verification failed |
MIT - Copperline Labs LLC
FAQs
Official TypeScript SDK for Rendex β render HTML or Markdown to images, generate PDFs, capture screenshots, and monitor pages for changes with Rendex Watch
The npm package @copperline/rendex receives a total of 9 weekly downloads. As such, @copperline/rendex popularity was classified as not popular.
We found that @copperline/rendex demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 1 open source maintainer collaborating on the project.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.

Company News
Allow myself to introduce... myself.

Research
/Security News
A Twitch browser extension on Chrome and Firefox forwards usersβ live OAuth session tokens through proxies controlled by a Russian bot service.