rtrvr.ai
DocsChrome / Cloud / API / MCP
Search docs⌘ K

Guide

Webhooks

Trigger workflows from external systems and receive async completion callbacks with signatures and retries.

READ6 MIN
n8n + Extension Integration
Cloud Browser API from n8n

Webhook-triggered tasks and API runs need a paid plan and use credits for the resources they consume, and so does running rtrvr's agent in your Chrome through API or MCP. Receiving a completion callback does not make an API run part of Free Mode. See plan and usage details.

Webhooks let external systems trigger rtrvr workflows via HTTP POST and let rtrvr send completion/failure callbacks back to your infrastructure. Use this for Zapier, Make, n8n, backend jobs, and server-to-server pipelines.

01

Platform Compatibility

PlatformHTTP TimeoutCompatibilityRecommended Approach
n8n100s (Cloud)ExcellentDirect calls work for most tasks
Make.comUp to 300sExcellentSet timeout to 120s+
Zapier30s fixedUse callbacksProvide webhookUrl for async results
02

Inbound Webhooks (Zapier, Make, n8n → rtrvr)

Any service that can send an HTTP POST can trigger rtrvr.ai workflows. Use the MCP endpoint to control your logged-in browser, or the /agent endpoint for cloud browser execution.

For a fixed task, the Cloud dashboard's Triggers panel (Cloud → Triggers) mints a per-trigger URL (POST https://mcp.rtrvr.ai/v1/webhooks/trigger/{id}, Bearer API key) whose target is a saved tool, a past cloud run, or a prompt stored on the trigger: a prompt trigger runs that prompt on every POST and appends the body's optional input to it.

Every endpoint here, trigger URLs included, takes your API key as Authorization: Bearer rtrvr_…, as the bare key (Authorization: rtrvr_…), or in an x-api-key header. In n8n, Make or Zapier "Header Auth" credentials, set Name to Authorization and Value to your key (the Bearer prefix is optional), or set Name to x-api-key.

MCP Endpoint (Your Browser)

text
POST https://mcp.rtrvr.ai Headers: Authorization: Bearer rtrvr_your_api_key Content-Type: application/json Body: { "tool": "planner" | "extract" | "act" | "crawl" | "replay_workflow" | ..., "params": { ... tool-specific parameters ... }, "deviceId": "optional_device_id", "webhookUrl": "https://your-server.com/callback" // optional: receive results }

Agent Endpoint (Cloud Browser)

bash
POST https://api.rtrvr.ai/agent Headers: Authorization: Bearer YOUR_API_KEY Content-Type: application/json Body: { "input": "Extract company info and contact details", "urls": ["https://example.com"], "webhookUrl": "https://your-server.com/callback", "response": { "verbosity": "final" } }

n8n Integration

n8n Cloud has a 100-second timeout: comfortably above most rtrvr task durations. Use either endpoint depending on whether you need your logged-in browser or a cloud browser.

json
// n8n → MCP (your logged-in browser) { "method": "POST", "url": "https://mcp.rtrvr.ai", "body": { "tool": "planner", "params": { "user_input": "{{ $json.task_description }}", "tab_urls": ["{{ $json.target_url }}"] }, "webhookUrl": "{{ $node.Webhook.url }}" } } // n8n → /agent (cloud browser) { "method": "POST", "url": "https://api.rtrvr.ai/agent", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer {{ $credentials.rtrvrApiKey }}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ { "name": "input", "value": "={{ $json.taskDescription }}" }, { "name": "urls", "value": "={{ [$json.targetUrl] }}" } ] } }

Make (Integromat) Integration

  • 01

    Add an "HTTP > Make a request" module

  • 02

    URL: https://mcp.rtrvr.ai | Method: POST

  • 03

    Headers: Authorization (Bearer token), Content-Type (application/json)

  • 04

    Body type: Raw, Content type: JSON

  • 05

    Request content: Your tool + params JSON

Zapier Integration

Zapier has a fixed 30-second HTTP timeout. Use the webhook pattern: Zap 1 triggers rtrvr with a webhookUrl pointing to a Catch Hook in Zap 2, which receives and processes the results.

  • 01

    Add a "Webhooks by Zapier" action to your Zap

  • 02

    Select "POST" as the method

  • 03

    Set URL to: https://mcp.rtrvr.ai

  • 04

    Add headers: Authorization = Bearer rtrvr_your_api_key, Content-Type = application/json

  • 05

    Set Data to your JSON payload (tool + params)

  • 06

    Set webhookUrl to a Catch Hook URL in a second Zap

json
// Example: Extract data when a new row is added to Google Sheets { "tool": "extract", "params": { "user_input": "Extract the company name, employee count, and funding info", "tab_urls": ["{{Google Sheets Row URL}}"] }, "webhookUrl": "https://hooks.zapier.com/hooks/catch/123/abc/" }

Available Tools

ToolUse CaseExecution
agentEnd-to-end task from one prompt; your signed-in Chrome when connected, else a cloud browser (target overrides)Local or cloud browser
scrapeRead pages (text + accessibility tree); same routing as agentLocal or cloud browser
plannerComplex multi-step tasks from natural languageLocal or cloud browser
extractStructured data extraction with optional schemaLocal or cloud browser
actPage interactions (click, type, navigate)Local or cloud browser
crawlMulti-page crawling with extractionLocal or cloud browser
replay_workflowRe-run a previous workflow by ID or URLLocal or cloud browser
get_browser_tabsList open tabsLocal browser only
user_<toolName>Run one of your saved tools (subroutines, custom JavaScript tools) with its parameters; your signed-in Chrome when connected, else a cloud browserLocal or cloud browser

Saved tools no longer need your Chrome open. A user_<toolName> call (REST tool, or the MCP tool of the same name) runs on your extension when a device is connected and falls back to a cloud browser otherwise; pass target: "cloud" to force the cloud browser or target: "device" to keep the old behaviour (a 503 when nothing is connected). Cloud runs open the tool's page with its stored website session, bill browser time and inference like an agent run (creditsUsed is in the response), and answer 202 accepted with a trajectoryId when the tool is still running after ~25 seconds: add a webhookUrl to receive the result, or read it from Cloud executions. Cloud execution needs an API key with the cloud agent capability.

03

Outbound Webhooks (rtrvr → Your Server)

Include a webhookUrl in any API request to receive results when the workflow completes. rtrvr.ai will POST the full response to your endpoint.

Enabling Outbound Webhooks

bash
curl -X POST "https://mcp.rtrvr.ai" \ -H "Authorization: Bearer rtrvr_xxx" \ -H "Content-Type: application/json" \ -d '{ "tool": "planner", "params": { "user_input": "Find pricing for iPhone 16 Pro on Apple.com", "tab_urls": ["https://apple.com"] }, "webhookUrl": "https://your-server.com/rtrvr-callback", "webhookSecret": "your_hmac_secret" }'
04

Webhook Payloads

Success Payload

json
{ "event": "workflow.completed", "timestamp": "2025-01-15T12:00:00.000Z", "requestId": "req_abc123xyz", "success": true, "data": { "taskCompleted": true, "output": { ... }, "extractedData": [ ... ], "creditsUsed": 5 }, "metadata": { "tool": "planner", "deviceId": "dj75mmaTWP0", "executionTime": 15234, "creditsRemaining": 9995 }, "originalRequest": { "tool": "planner", "params": { ... } } }

Error Payload

json
{ "event": "workflow.failed", "timestamp": "2025-01-15T12:00:00.000Z", "requestId": "req_abc123xyz", "success": false, "error": { "message": "Device offline: no available browser extensions", "code": "DEVICE_UNAVAILABLE", "details": { ... } }, "metadata": { "tool": "planner", "executionTime": 1234 } }
05

Verifying Webhook Signatures

If you provide a webhookSecret, rtrvr.ai signs the payload with HMAC-SHA256. Verify it to ensure authenticity:

typescript
// Express.js import crypto from 'crypto'; app.post('/rtrvr-callback', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-rtrvr-signature'] as string; const timestamp = req.headers['x-rtrvr-timestamp'] as string; // Reject stale timestamps (> 5 minutes) if (Date.now() - parseInt(timestamp) > 300000) { return res.status(400).json({ error: 'Timestamp too old' }); } const payload = timestamp + '.' + req.body.toString(); const expected = crypto .createHmac('sha256', process.env.RTRVR_WEBHOOK_SECRET!) .update(payload) .digest('hex'); if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) { return res.status(401).json({ error: 'Invalid signature' }); } const data = JSON.parse(req.body.toString()); // Process asynchronously — respond 200 immediately res.status(200).json({ received: true }); processWebhook(data); });
python
# Flask import hmac, hashlib, time, os from flask import Flask, request, jsonify WEBHOOK_SECRET = os.environ['RTRVR_WEBHOOK_SECRET'] @app.route('/rtrvr-callback', methods=['POST']) def handle_webhook(): signature = request.headers.get('X-Rtrvr-Signature') timestamp = request.headers.get('X-Rtrvr-Timestamp') if abs(time.time() * 1000 - int(timestamp)) > 300000: return jsonify({'error': 'Timestamp too old'}), 400 payload = f"{timestamp}.{request.data.decode()}" expected = hmac.new(WEBHOOK_SECRET.encode(), payload.encode(), hashlib.sha256).hexdigest() if not hmac.compare_digest(signature, expected): return jsonify({'error': 'Invalid signature'}), 401 data = request.json return jsonify({'received': True}) # Process async
06

Retry Behavior

Failed deliveries are retried with exponential backoff:

  • 01

    Attempt 1: Immediate

  • 02

    Attempt 2: After 5 seconds

  • 03

    Attempt 3: After 30 seconds

  • 04

    Attempt 4: After 2 minutes

  • 05

    Attempt 5: After 10 minutes (final)

07

Common Patterns

Lead Enrichment Pipeline

New lead in CRM → rtrvr extracts company data → webhook returns enriched info → update CRM record.

json
// Trigger: New HubSpot contact // Action: POST to https://api.rtrvr.ai/agent { "input": "Visit this company website and extract: company size, industry, tech stack, and key contacts", "urls": ["{{contact.company_website}}"], "webhookUrl": "https://hooks.zapier.com/catch/123/enrich/", "response": { "verbosity": "final" } } // Webhook receives enriched data → Update CRM

Browser Trigger → Sheet Log (Zero Server)

The simplest pattern: monitor a site for notifications and log events to Google Sheets. No server, no API, no webhook endpoint needed.

  • 01

    Create a workflow that extracts data from the site and appends to a Google Sheet

  • 02

    Set up a Browser Trigger on that site with appropriate filters

  • 03

    Configure sheet output to "Append to same sheet on each run"

  • 04

    Every matching notification adds a row: building a running log automatically

Scheduled Price Monitoring

Cron schedule → rtrvr checks competitor prices → compare with previous data → alert if changed.

json
// Schedule: Daily at 9am via n8n Cron node // Action: POST to https://api.rtrvr.ai/scrape { "urls": [ "https://competitor1.com/pricing", "https://competitor2.com/pricing" ] } // Compare extracted prices with yesterday's data // If changed → Send Slack/email notification

Browser Trigger + Outbound Webhook (Hybrid)

text
Flow: 1. Browser Trigger monitors slack.com for "deployment failed" notifications 2. Trigger fires → workflow extracts error details from the Slack thread 3. Workflow calls your server via rtrvr.ai API with webhookUrl set 4. Server receives error details → creates a Jira ticket automatically Result: Slack notification → browser extraction → server-side ticket creation No Slack API required: the browser does the heavy lifting

Authenticated Data Sync (MCP)

Your app triggers → rtrvr uses your logged-in browser via MCP → data synced to your database.

json
// Trigger: Webhook from your application // Action: POST to https://mcp.rtrvr.ai { "tool": "extract", "params": { "user_input": "Export my order history from the last 30 days", "tab_urls": ["https://vendor-portal.com/orders"] }, "webhookUrl": "https://your-app.com/api/orders/sync" } // Your browser navigates using your login session // Results sent to webhook → stored in database

Zapier → rtrvr → Zapier (Round-trip)

  • 01

    Zap 1: New Google Form submission → POST to mcp.rtrvr.ai (include webhookUrl pointing to Zap 2)

  • 02

    Zap 2: Catch Hook receives results → Add row to Google Sheets

Slack Command → rtrvr → Slack Message

typescript
app.post('/slack/commands', async (req, res) => { const { text, response_url } = req.body; res.status(200).json({ text: '🔄 Running extraction...' }); // Ack < 3s await fetch('https://mcp.rtrvr.ai', { method: 'POST', headers: { 'Authorization': 'Bearer rtrvr_xxx', 'Content-Type': 'application/json' }, body: JSON.stringify({ tool: 'extract', params: { user_input: text, tab_urls: [extractUrlFromText(text)] }, webhookUrl: 'https://your-server.com/slack-callback', webhookMetadata: { response_url }, }), }); }); app.post('/slack-callback', async (req, res) => { const { data, originalRequest } = req.body; const { response_url } = originalRequest.webhookMetadata; await fetch(response_url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: `✅ Extracted: ${JSON.stringify(data.extractedData, null, 2)}`, }), }); res.status(200).json({ received: true }); });
08

Choosing the Right Approach

ApproachTrigger SignalBest ForAvailability
Browser TriggersPush notification in a tabSites without APIs: social media, chat, SaaS dashboardsWhile Chrome is open
SchedulesCron / interval timerPeriodic collection, monitoring, recurring reportsChrome or 24/7 cloud
Inbound WebhooksHTTP POST from external serviceZapier / Make / n8n, CI/CD, server-to-server24/7 cloud
09

Best Practices

  • 01

    Verify signatures on every callback in production

  • 02

    Implement idempotency to handle retries safely

  • 03

    Use HTTPS-only endpoints

  • 04

    Pass webhookMetadata for correlation IDs and routing context

YOUR NEXT RUN

Run the example on a real site.

Use Chrome for the page in front of you. Use Cloud when the run should continue on a schedule or across many pages.