Preview Tools
Deploy any app to an ephemeral URL, screenshot it, and compare changes — all via API.
Which Tool Should I Use?
| Feature | riddle_preview | server_preview | build_preview |
|---|---|---|---|
| Speed | ~5s | ~30–60s | ~1–3min |
| Server process | No (static only) | Yes | Yes |
| Docker image | — | Stock (pull) | Custom (build) |
| System packages | — | — | ✓ |
| Image caching | — | — | ✓ (30 min default) |
| Security audit | — | — | ✓ |
| Playwright scripts | — | ✓ | ✓ |
| Env vars | — | ✓ | ✓ |
| Preview URL | ✓ (24hr) | — | — |
riddle_preview — Static Hosting
Deploy built static files (HTML, CSS, JS) to an ephemeral URL at preview.riddledc.com. The preview expires after 24 hours. Best for SPAs, Vite builds, Next.js static exports, or any pre-built frontend.
How It Works
- Tar your build output directory
- Upload to Riddle
- Get a live URL in ~5 seconds
- Screenshot it with any Riddle tool
Basic Example
const response = await fetch("https://api.riddledc.com/v1/preview", {
method: "POST",
headers: {
"Authorization": `Bearer ${RIDDLE_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
directory: "/path/to/build/output",
framework: "spa" // "spa" (default) or "static"
})
});
const { url, id } = await response.json();
// url: "https://pv-a1b2c3d4.preview.riddledc.com"
// id: "pv_a1b2c3d4" (use to delete early)Parameters
| Parameter | Type | Description |
|---|---|---|
directory | string | Absolute path to build output (must contain index.html) |
framework | string | "spa" (default) — all routes serve index.html. "static" — file-based routing. |
dist/ or out/ folder with static files. You want a shareable URL that works for 24 hours.Delete Early
Previews auto-expire after 24 hours, but you can clean up immediately:
await fetch("https://api.riddledc.com/v1/preview/pv_a1b2c3d4", {
method: "DELETE",
headers: { "Authorization": `Bearer ${RIDDLE_API_KEY}` }
});riddle_server_preview — Server Apps
Run a server-side application inside an isolated Docker container and screenshot it with Playwright. Uses stock images from Docker Hub — no Dockerfile needed. Perfect for Next.js, Express, Django, FastAPI, Rails, and any app that needs a running server process.
How It Works
- Tar your project directory and upload it
- Pull a stock Docker image (e.g.
node:20-slim) - Start your server inside the container
- Wait for the readiness check to pass
- Take a Playwright screenshot
- Return the screenshot and logs
Basic Example
const response = await fetch("https://api.riddledc.com/v1/run", {
method: "POST",
headers: {
"Authorization": `Bearer ${RIDDLE_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
server_preview: {
directory: "/path/to/my-express-app",
image: "node:20-slim",
command: "npm start",
port: 3000,
path: "/dashboard",
env: { NODE_ENV: "production" },
viewport: { width: 1920, height: 1080 }
}
})
});With Authentication & Custom Scripts
{
server_preview: {
directory: "/path/to/app",
image: "node:20-slim",
command: "npm start",
port: 3000,
// Inject localStorage tokens before page loads
localStorage: {
"auth_token": "eyJhbGciOiJIUzI1NiJ9...",
"user_id": "12345"
},
// Sensitive env vars — stored securely, deleted after use
sensitive_env: {
DATABASE_URL: "postgres://...",
API_SECRET: "sk-..."
},
// Wait for React hydration before screenshotting
wait_for_selector: "#app[data-hydrated]",
// Run a Playwright script after server is ready
script: `
await page.click('button.load-data');
await page.waitForSelector('.data-table');
await saveScreenshot('with-data');
`,
// Emulate dark mode
color_scheme: "dark",
// Readiness check config
readiness_path: "/health",
readiness_timeout: 30,
timeout: 120
}
}Key Parameters
| Parameter | Type | Description |
|---|---|---|
directory | string | Path to your project |
image | string | Docker image to run (node:20-slim, python:3.12-slim, etc.) |
command | string | Command to start your server |
port | number | Port your server listens on |
path | string | URL path to screenshot (default: /) |
env | object | Non-sensitive environment variables |
sensitive_env | object | Secrets — stored securely, deleted after use |
localStorage | object | Key-value pairs injected before page load |
script | string | Playwright script to run after server is ready |
wait_for_selector | string | CSS selector to wait for before screenshotting |
color_scheme | string | "dark" or "light" — applied before navigation |
viewport | object | { width, height } — default 1920×1080 |
readiness_path | string | Health check endpoint to poll |
timeout | number | Max execution time in seconds (default: 120) |
Common Docker Images
Node.js
node:20-slim
Express, Fastify, Next.js, Nuxt
Python
python:3.12-slim
Django, FastAPI, Flask
Ruby
ruby:3.3-slim
Rails, Sinatra
riddle_build_preview — Custom Builds
Build a Docker image from your own Dockerfile, run the server, and screenshot it. Use this when you need custom system packages, compiled languages, multi-stage builds, or anything beyond a stock runtime image.
How It Works
- Tar your project (must include a
Dockerfile) - Build the Docker image on the worker
- Start the container and wait for readiness
- Take a Playwright screenshot
- Cache the built image for fast re-runs
Basic Example
const response = await fetch("https://api.riddledc.com/v1/run", {
method: "POST",
headers: {
"Authorization": `Bearer ${RIDDLE_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
build_preview: {
directory: "/path/to/project", // Must contain Dockerfile
command: "npm start",
port: 3000,
build_args: { NODE_ENV: "production" },
keep_image_minutes: 30, // Cache the built image
timeout: 180 // Includes build time
}
})
});With Security Audit
Enable audit: true to run a security scan on your code and dependencies. Returns a detailed report of findings, risk flags, and dependency inventory.
{
build_preview: {
directory: "/path/to/project",
command: "python server.py",
port: 8000,
audit: true, // Security scan
timeout: 180
}
}
// Response includes:
// {
// audit: {
// security_findings: [...],
// deps_extracted: { runtime: { pip: [...], npm: [...] } },
// code_summary: { files: [...], total_lines: 1234 },
// risk_flags: [{ level: "info", reason: "..." }]
// }
// }Additional Parameters
Supports all riddle_server_preview parameters plus:
| Parameter | Type | Description |
|---|---|---|
build_args | object | Docker --build-arg key-value pairs |
keep_image_minutes | number | Cache built image on worker (default: 30, max: 120, 0 = delete immediately) |
audit | boolean | Run security audit on code + dependencies |
exclude | string[] | Glob patterns to exclude from tarball (default: [".git", "*.log"]) |
keep_image_minutes: 30 to avoid rebuilding on every run. The built image stays on the worker, so subsequent runs skip the Docker build step entirely. Set to 0 if you always want a fresh build.timeout: 600 (max). Cached images skip the build step, so subsequent runs are much faster.Screenshotting Previews
After deploying with riddle_preview, you get a live URL. Screenshot it with any Riddle tool:
Simple Screenshot
// After riddle_preview returns a URL
const screenshot = await fetch("https://api.riddledc.com/v1/run", {
method: "POST",
headers: {
"Authorization": `Bearer ${RIDDLE_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
url: "https://pv-a1b2c3d4.preview.riddledc.com"
})
});Interactive Testing
// Run a Playwright script against the preview
{
script: `
await page.goto("https://pv-a1b2c3d4.preview.riddledc.com");
await page.click('button#get-started');
await page.waitForSelector('.onboarding-flow');
await saveScreenshot('onboarding');
`,
timeout_sec: 60
}Before/After Visual Diffs
The real power of preview tools: deploy two versions and compare them pixel-by-pixel. Perfect for verifying CSS changes, layout tweaks, or redesigns.
The Workflow
// 1. Deploy the "before" version
const before = await riddlePreview({ directory: "./build-before" });
// 2. Deploy the "after" version
const after = await riddlePreview({ directory: "./build-after" });
// 3. Compare them
const diff = await fetch("https://api.riddledc.com/v1/run", {
method: "POST",
headers: {
"Authorization": `Bearer ${RIDDLE_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
visual_diff: {
url_before: before.url,
url_after: after.url,
full_page: true,
threshold: 0.1 // Pixel match sensitivity (0–1)
}
})
});
// Returns:
// {
// change_percentage: 2.3,
// changed_pixels: 4521,
// images: {
// before: "https://...",
// after: "https://...",
// diff: "https://..." ← highlighted changes
// }
// }selector to diff just a specific component instead of the full page. Set delay_ms to wait for animations to settle before capturing.Start Previewing
Get an API key and deploy your first preview in under a minute.