Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run Playwright outside Convex, and use Convex as the authenticated control plane, durable job store, and result coordinator. Convex HTTP actions can accept requests and call Convex functions, but they do not provide a Node.js runtime for Chromium. Put browser execution in a Node-capable worker or a managed browser service, then report status and results back to Convex.

The production shape: Convex coordinates, a worker drives the browser

A reliable user-facing automation feature separates four responsibilities:

  • Frontend: collects the user’s request, shows job progress, and reads results through the production Convex deployment.
  • Convex: authenticates the caller, validates allowed destinations and actions, stores a job record, and exposes mutations or queries for status.
  • Worker or browser service: runs Playwright, manages browser sessions, enforces timeouts, and produces artifacts or extracted data.
  • Callback path: lets the worker mark the Convex job as succeeded or failed without exposing browser-control credentials to the browser client.

The request should normally become a durable job rather than a long, synchronous HTTP response. Browser startup, navigation, login flows, downloads, and sites that never become idle can exceed an interactive request’s useful lifetime. Persisting queued, running, succeeded, and failed states also makes retries and user-visible progress explicit.

Why Convex is not the Chromium host

Convex HTTP actions use Fetch API Request and Response objects and can call Convex queries, mutations, and actions. They run in the same Convex environment as those functions, not in a general Node.js process. They do not expose Node-specific APIs, including the normal local process and filesystem assumptions used to install and launch Playwright browsers. Treat an HTTP action as ingress and orchestration, not as a place to run Chromium.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

Convex documents a 20 MB limit for both HTTP-action requests and responses. HTTP actions are not automatically retried when they fail. Those constraints are another reason to pass a small job description through Convex and store large screenshots, PDFs, or downloaded files in object storage or a dedicated artifact service.

A minimal job contract

Define a stable contract before choosing a worker host. A useful job contains an owner, a constrained target, an operation, timestamps, and an idempotency key. Never accept arbitrary code from an end user.

// convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  browserJobs: defineTable({
    userId: v.string(),
    url: v.string(),
    operation: v.union(v.literal("title"), v.literal("screenshot")),
    status: v.union(
      v.literal("queued"), v.literal("running"),
      v.literal("succeeded"), v.literal("failed")
    ),
    result: v.optional(v.object({
      title: v.optional(v.string()),
      artifactUrl: v.optional(v.string())
    })),
    error: v.optional(v.string()),
    idempotencyKey: v.string(),
    createdAt: v.number(),
    updatedAt: v.number()
  }).index("by_user", ["userId"])
});

In a real application, derive userId from your authentication provider rather than trusting a value sent by the client. Validate URL schemes, permitted hosts, operation names, and maximum navigation time before enqueueing.

Convex functions for enqueueing and completion

A mutation creates the job. A second, server-authorized mutation records completion. Keep the completion mutation idempotent: a worker retry should not overwrite a newer terminal state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
// convex/browserJobs.ts
import { mutation, query } from "./_generated/server";
import { v } from "convex/values";

export const create = mutation({
  args: { url: v.string(), operation: v.union(v.literal("title"), v.literal("screenshot")), idempotencyKey: v.string() },
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new Error("Unauthenticated");
    if (!args.url.startsWith("https://")) throw new Error("Only HTTPS URLs are allowed");
    const now = Date.now();
    const existing = await ctx.db.query("browserJobs").withIndex("by_user", q => q.eq("userId", identity.subject)).collect();
    const duplicate = existing.find(j => j.idempotencyKey === args.idempotencyKey);
    if (duplicate) return duplicate._id;
    return await ctx.db.insert("browserJobs", {
      userId: identity.subject, url: args.url, operation: args.operation,
      status: "queued", idempotencyKey: args.idempotencyKey,
      createdAt: now, updatedAt: now
    });
  }
});

export const complete = mutation({
  args: {
    jobId: v.id("browserJobs"),
    status: v.union(v.literal("succeeded"), v.literal("failed")),
    result: v.optional(v.object({ title: v.optional(v.string()), artifactUrl: v.optional(v.string()) })),
    error: v.optional(v.string())
  },
  handler: async (ctx, args) => {
    const job = await ctx.db.get(args.jobId);
    if (!job || (job.status !== "queued" && job.status !== "running")) return;
    await ctx.db.patch(args.jobId, { status: args.status, result: args.result, error: args.error, updatedAt: Date.now() });
  }
});

export const get = query({
  args: { jobId: v.id("browserJobs") },
  handler: (ctx, args) => ctx.db.get(args.jobId)
});

Your dispatch mechanism can be a queue, a private HTTP endpoint, or a worker polling for queued jobs. Authenticate the worker-to-Convex call separately; do not expose an unrestricted completion endpoint.

Running Playwright in your own worker

The self-managed option puts a compatible Playwright package, browser binaries, and system dependencies in a worker image. Playwright’s browser versions track its package releases, so install browsers during image build and keep the package and binaries aligned.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
npm install playwright
npx playwright install --with-deps chromium

Playwright’s documentation illustrates that a browser build can consume hundreds of megabytes (for example, 281 MB for Chromium and 187 MB for Firefox in its installation examples). Account for image size, cold starts, concurrent contexts, browser updates, and isolation when selecting a worker platform.

// worker/runJob.mjs
import { chromium } from "playwright";

export async function runJob(job, report) {
  const browser = await chromium.launch({ headless: true });
  try {
    const page = await browser.newPage({
      viewport: { width: 1440, height: 900 },
      serviceWorkers: "block"
    });
    await page.goto(job.url, { waitUntil: "domcontentloaded", timeout: 30_000 });
    if (job.operation === "title") {
      await report({ status: "succeeded", result: { title: await page.title() } });
      return;
    }
    const path = `/tmp/${job.id}.png`;
    await page.screenshot({ path, fullPage: true });
    const artifactUrl = await uploadArtifact(path); // Use private object storage.
    await report({ status: "succeeded", result: { artifactUrl } });
  } catch (error) {
    await report({ status: "failed", error: error instanceof Error ? error.message : "Browser failed" });
  } finally {
    await browser.close();
  }
}

Set hard limits around navigation, total job duration, downloaded bytes, redirects, and permitted domains. Close every context in a finally block. For untrusted destinations, isolate workers and block access to cloud metadata endpoints and internal network ranges.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Using a managed or self-hosted browser

A managed browser service removes browser patching and much of the host-level operations work. The application still owns authorization, job limits, and secrets. Browserless documents connecting Playwright to managed browsers by replacing chromium.launch() with chromium.connectOverCDP():

import { chromium } from "playwright";

const browser = await chromium.connectOverCDP(
  `wss://your-browser-provider.example?token=${process.env.BROWSER_TOKEN}`
);
const context = browser.contexts()[0] ?? await browser.newContext();
const page = await context.newPage();
await page.goto("https://example.com", { waitUntil: "domcontentloaded" });

CDP supports most Playwright scripts, but Browserless documents cases where particular features and browser choices require Playwright’s native protocol. Verify protocol compatibility for the exact automation before committing to a provider. Provider pricing, quotas, regional availability, and session limits vary and are not established here.

Self-hosting a browser service, such as with a documented Browserless Docker image, gives you operational ownership. Put it on a private network or configure endpoint authentication. A reachable deployment without a token can expose browser endpoints, including an endpoint capable of running supplied code. Add resource limits, patching, monitoring, and incident response to the service’s runbook.

Deploying Convex safely

Development, preview, staging, and production

Convex provides a development deployment for each team member and one shared production deployment per project. Use a preview deployment for branch validation. For a long-lived staging environment with stable data and credentials, use a separate Convex project rather than treating a short-lived preview as staging.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

What npx convex deploy does

Run deployment from CI with a deployment key or from a controlled release environment:

npx convex deploy

The CLI typechecks, generates code, bundles functions, and pushes functions, indexes, and schema. Coordinate this backend deployment with your frontend host so the released bundle points to the intended production Convex URL. Convex documents CONVEX_CLOUD_URL for Convex clients and CONVEX_SITE_URL for HTTP actions.

Backward-compatible rollouts

Convex’s production guidance says, “Functions should be backwards compatible.” An older website bundle can remain active after a backend deploy, and scheduled functions run the currently deployed code with the arguments captured when they were scheduled. Add fields before requiring them, accept old and new argument shapes during a migration, and keep queued jobs readable by both versions until the rollout drains.

Secrets and environment variables

Set browser-provider tokens separately for development, preview or staging, and production. Convex environment variables are per deployment, so a development deployment can point at a test browser while production uses a restricted provider account. Declare expected variables in convex/convex.config.ts when you want typed access and deploy-time validation.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Current Convex documentation lists limits of 512 variables per deployment, 512 KiB for combined variable-name and value capacity, and 8 KiB for one value. These are product limits, not a reason to put certificates or large payloads in environment variables. Store artifacts elsewhere, rotate provider tokens, and never put private credentials in public frontend environment variables.

Authentication, authorization, and abuse controls

  • Authenticate the user before creating a job and authorize access to every job read.
  • Allow-list destinations or enforce a clear URL policy; reject non-HTTPS schemes and internal IP ranges.
  • Limit jobs per user, concurrent sessions, navigation time, page size, and artifact retention.
  • Redact cookies, authorization headers, page content, and provider errors from logs.
  • Keep browser credentials only in the worker or Convex server-side environment; never ship them in frontend JavaScript.
  • Use an idempotency key so double-clicks and client retries do not create duplicate work.

Performance and reliability decisions

Make latency visible

Record queue time, browser-start time, navigation time, and artifact-upload time. Return a job ID immediately, subscribe to Convex status updates, and show a useful pending state instead of holding an HTTP request open.

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

Retry only safe stages

Retry transient worker startup, provider connection, and upload failures with a bounded backoff. Do not blindly replay a workflow that submits a form, sends a message, or purchases an item. Mark attempts and make side effects idempotent where the target site permits it.

Control concurrency

Browser processes are memory-intensive. Limit concurrent contexts per worker, recycle a browser after repeated crashes, and apply a queue back-pressure policy. If a page never reaches network idle, use an explicit selector or delay with a maximum total timeout rather than waiting forever.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting

“Cannot find module” or browser executable errors

The worker image has the Playwright package but not its matching browser binaries or system dependencies. Run npx playwright install --with-deps chromium during the image build, pin compatible versions, and rebuild after upgrading Playwright.

HTTP action works locally but cannot launch Chromium

That is an execution-boundary mistake: HTTP actions are not a Node browser host. Move launch code into the worker or use a remote browser connection; leave the action responsible for validation and coordination.

Jobs remain queued

Check that the dispatcher can read the production deployment, that its Convex URL and deployment credentials match the environment, and that the worker acknowledges a job before starting. Add a lease or heartbeat so a crashed worker does not leave work permanently claimed.

Duplicate screenshots or repeated side effects

Use the idempotency key in the enqueue mutation, persist an attempt ID, and make completion updates conditional on non-terminal status. For side-effecting actions, require an explicit confirmation and design a target-specific deduplication strategy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

Large results fail

Convex HTTP actions have a 20 MB request and response limit. Upload the artifact directly from the worker to private object storage, then save only metadata and a short-lived access URL in Convex.

Remote connection fails or a feature behaves differently

Confirm the provider token, WebSocket egress, browser choice, and protocol. CDP does not guarantee identical support for every Playwright feature; test the exact script with the provider’s documented protocol.

Or skip the browser setup

For screenshot-oriented automation, ScreenshotNeo is a ready API and MCP server. It accepts a URL and returns PNG, JPEG, WebP, or PDF without requiring you to package Chromium. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing outcome. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

Use the API from your worker, Convex action, or another trusted server. Keep the access key server-side. Full option names and signed-link, webhook, bulk, PDF, device, CSS, JavaScript, cookie, header, caching, and blocking controls are documented at ScreenshotNeo’s API documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Every plan includes every feature. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Other plans are Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free. Create a free ScreenshotNeo account to start with 1,000 screenshots a month and no card.

Deployment checklist

  1. Create separate Convex development, preview or staging, and production configurations.
  2. Define and validate the job schema, ownership checks, idempotency key, and allowed operations.
  3. Choose a worker, managed browser, or secured self-hosted endpoint; document protocol support.
  4. Install matching Playwright browsers if self-hosting and set explicit timeouts.
  5. Store provider credentials per deployment and keep them out of frontend bundles.
  6. Deploy backend changes with npx convex deploy from a controlled pipeline.
  7. Test old frontend bundles, scheduled jobs, retries, oversized results, and worker failure.
  8. Monitor queue age, success rate, browser crashes, provider errors, and artifact retention.

Frequently Asked Questions

Can a Convex client call a Convex function over HTTP?

For a caller you control, Convex documentation says an HTTP action is not required merely to call Convex functions over HTTP; use a Convex client instead. Use an HTTP action when you need an external HTTP endpoint.

Should I use a preview deployment as permanent staging?

Use preview deployments for branch validation. Convex documents a separate project as the route for longer-lived staging with stable data and credentials.

Where should browser-provider credentials live?

Keep them in trusted worker or Convex server-side environment variables, configured separately for each deployment. They should never be embedded in frontend code.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What happens if a scheduled automation runs during a deployment?

Convex runs scheduled functions with the currently deployed code and the arguments captured when they were scheduled, so keep function arguments and behavior backward compatible during rollout.

The Bottom Line

Ship the browser as a separate, authenticated execution service; let Convex own identity, jobs, state, and coordination. This boundary keeps Chromium operational concerns out of Convex while giving users durable, observable automation.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.