Browser Workflow integrations
Stream large batch manifests and verify Browser Workflow webhooks.
This guide covers two integration patterns for the Browser Workflow Data API: streaming a large NDJSON manifest and validating webhook deliveries.
Stream a 100,000-item manifest with Node.js
The first line is the batch header. Each following line is an item containing the variables for one workflow run. The request is streamed instead of building a 100,000-item array in memory.
import { randomUUID } from "node:crypto";
import { Readable } from "node:stream";
const baseUrl = process.env.BROWSER_WORKFLOW_API_URL ?? "https://api.runharvester.com";
const apiKey = process.env.BROWSER_WORKFLOW_API_KEY;
const projectId = process.env.BROWSER_WORKFLOW_PROJECT_ID;
const environmentId = process.env.BROWSER_WORKFLOW_ENVIRONMENT_ID;
const workflowId = process.env.BROWSER_WORKFLOW_ID;
const versionId = process.env.BROWSER_WORKFLOW_VERSION_ID;
if (!apiKey || !projectId || !environmentId || !workflowId || !versionId) {
throw new Error("Browser Workflow configuration is incomplete");
}
function* manifestLines() {
yield JSON.stringify({
type: "batch",
workflow_version_id: versionId,
priority: 1,
configured_concurrency: 4,
}) + "\n";
for (let page = 1; page <= 100_000; page += 1) {
yield JSON.stringify({ type: "item", variables: { page } }) + "\n";
}
}
const response = await fetch(
`${baseUrl}/api/v1/browser/projects/${projectId}/environments/${environmentId}/workflows/${workflowId}/batches/manifest`,
{
method: "POST",
headers: {
"content-type": "application/x-ndjson",
"x-api-key": apiKey,
"idempotency-key": randomUUID(),
},
body: Readable.toWeb(Readable.from(manifestLines())),
duplex: "half",
},
);
if (!response.ok) throw new Error(`Manifest submission failed: ${response.status}`);
console.log(await response.json());The manifest endpoint validates each line as it arrives and accepts at most 100,000 items. Keep the first line as the batch header and use item lines for workflow variables. Use the same Idempotency-Key when retrying an uncertain submission.
Verify a webhook in Python
Verify the signature against the raw request body before parsing JSON or dispatching the event:
import hashlib
import hmac
def verify(headers: dict[str, str], body: bytes, signing_secret: str) -> bool:
timestamp = headers.get("x-browser-workflow-timestamp")
received = headers.get("x-browser-workflow-signature")
if not timestamp or not received:
return False
expected = "v1=" + hmac.new(
signing_secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(received, expected)Reject stale timestamps using the freshness window configured by your application. Deduplicate on x-browser-workflow-event-id: deliveries are at-least-once, and a replay retains the same event ID. Store the signing secret securely; the create-webhook response returns it only once.
Last updated on