← Back to Docs

Preview Tools

Deploy any app to an ephemeral URL, screenshot it, and compare changes — all via API.

Which Tool Should I Use?

What are you deploying?
Static filesHTML, CSS, JS — already built
riddle_preview~5 seconds
Server appNode, Python, Ruby — stock runtime
riddle_server_preview~30–60 seconds
Custom buildDockerfile, system deps, compiled langs
riddle_build_preview~1–3 minutes
Featureriddle_previewserver_previewbuild_preview
Speed~5s~30–60s~1–3min
Server processNo (static only)YesYes
Docker imageStock (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

  1. Tar your build output directory
  2. Upload to Riddle
  3. Get a live URL in ~5 seconds
  4. 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

ParameterTypeDescription
directorystringAbsolute path to build output (must contain index.html)
frameworkstring"spa" (default) — all routes serve index.html. "static" — file-based routing.
💡 When to use riddle_previewYour app is already built and just needs hosting. You have a 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

  1. Tar your project directory and upload it
  2. Pull a stock Docker image (e.g. node:20-slim)
  3. Start your server inside the container
  4. Wait for the readiness check to pass
  5. Take a Playwright screenshot
  6. 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

ParameterTypeDescription
directorystringPath to your project
imagestringDocker image to run (node:20-slim, python:3.12-slim, etc.)
commandstringCommand to start your server
portnumberPort your server listens on
pathstringURL path to screenshot (default: /)
envobjectNon-sensitive environment variables
sensitive_envobjectSecrets — stored securely, deleted after use
localStorageobjectKey-value pairs injected before page load
scriptstringPlaywright script to run after server is ready
wait_for_selectorstringCSS selector to wait for before screenshotting
color_schemestring"dark" or "light" — applied before navigation
viewportobject{ width, height } — default 1920×1080
readiness_pathstringHealth check endpoint to poll
timeoutnumberMax 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

  1. Tar your project (must include a Dockerfile)
  2. Build the Docker image on the worker
  3. Start the container and wait for readiness
  4. Take a Playwright screenshot
  5. 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:

ParameterTypeDescription
build_argsobjectDocker --build-arg key-value pairs
keep_image_minutesnumberCache built image on worker (default: 30, max: 120, 0 = delete immediately)
auditbooleanRun security audit on code + dependencies
excludestring[]Glob patterns to exclude from tarball (default: [".git", "*.log"])
💡 Image CachingSet 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 includes build timeThe default timeout is 180 seconds. Complex multi-stage builds may need more — set 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

Deploy "before"Make changesDeploy "after"Visual diff
// 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
//   }
// }
💡 Pro tipUse 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.