loading

Get Started

  • Overview
  • Quick Start
  • Workspace
  • Instant Preview
  • Rover in a Chrome Extension

Instruct & Customize

  • Instructing Rover
  • Journeys
  • Knowledge
  • Customize
  • Audience & Identity
  • Appearance

Connect AI

  • Connect Your AI
  • AI Discovery
  • Agent-to-Web (A2W)

Operate

  • Rover Analytics
  • Plan & Billing
  • Security & Policies
  • Roadmap

Reference

  • Configuration
  • API Reference
  • Instant Preview API
  • Examples

Platforms

  • Webflow
  • Wix

[ documentation ]

Examples

Common integration patterns for onboarding, checkout, forms, and more.

Start with the generated production tag. The inline rover('boot') examples below are advanced overrides for sites that deliberately manage part of the runtime configuration in code. In those examples the loader has no data-* boot attributes, so Rover boots exactly once.

Rover v2 task boundaries are strict: normal sends always start a fresh task boundary. Only ask_user answers continue the current boundary.

Canonical Setup

Default production install. Runtime policy, Activity, discovery, and billing config come from the Rover site record.

<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async
  data-site-id="my-site"
  data-public-key="pk_site_your_public_key"
  data-site-key-id="your_site_key_id"></script>

Journeys and async identity

Blend workspace journeys with runtime overrides and personalize greeting after login.

<script>
  (function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();
  rover('boot', {
    siteId: 'my-app',
    publicKey: 'pk_site_your_public_key',
    siteKeyId: 'your-site-key-id',
    allowedDomains: ['app.example.com'],
    // Workspace journeys are fetched by default via /v2/rover/session/open.
    // Optional override in boot config:
    ui: {
      shortcuts: [
        { id: 'onboard', label: 'Onboard me', prompt: 'Guide me through onboarding', routing: 'planner', enabled: true }
      ],
      greeting: { text: 'Hey {name}! Need setup help?', delay: 2000, duration: 8000 }
    },
  });

  // Later, when auth completes:
  rover('identify', { name: 'Alex', email: 'alex@example.com' });
</script>
<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async></script>

Voice dictation

Enable browser dictation so visitors can speak requests, edit the transcript, and manually send.

<script>
  (function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();
  rover('boot', {
    siteId: 'my-app',
    publicKey: 'pk_site_your_public_key',
    allowedDomains: ['app.example.com'],
    ui: {
      voice: {
        enabled: true,
        language: 'en-US',
        autoStopMs: 2600
      }
    }
  });
</script>
<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async></script>

Steering an in-flight task

While a task is running, the visitor's composer routes mid-run guidance through sendFeedback instead of starting a new task. Type or dictate guidance into the composer (placeholder switches to 'Guide Rover…'), or trigger steering programmatically from your own button.

<script>
  (function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();
  rover('boot', {
    siteId: 'my-app',
    publicKey: 'pk_site_your_public_key',
    allowedDomains: ['app.example.com'],
  });

  // Custom Steer button — only meaningful while a task is in flight.
  document.querySelector('#steer-button')?.addEventListener('click', () => {
    const ack = rover.sendFeedback('Actually use the search bar, not the menu');
    if (ack === null) {
      // No run in flight — sendFeedback is a no-op outside a run.
      console.log('No active task to steer.');
    }
  });
</script>
<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async></script>

Onboarding flow

Auto-routing setup with planner fallback only when ACT has no usable outcome.

<script>
  (function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();
  const isNewUser = !localStorage.getItem('onboarded');

  rover('boot', {
    siteId: 'my-app',
    publicKey: 'pk_site_your_public_key',
    allowedDomains: ['app.example.com'],
    openOnInit: isNewUser,
    taskRouting: {
      mode: 'auto',
      plannerOnActError: true, // Planner fallback runs only if ACT has no usable result
      actHeuristicThreshold: 5
    },
    checkpointing: { enabled: true, autoVisitorId: true },
  });
</script>
<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async></script>

Checkout assistant

Help visitors fill addresses, apply promos, and reach checkout. Payment and other consequential steps stop for explicit human confirmation.

<script>
  (function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();
  rover('boot', {
    siteId: 'my-store',
    publicKey: 'pk_site_your_public_key',
    allowedDomains: ['shop.example.com', 'checkout.example.com'],
    domainScopeMode: 'registrable_domain',
    allowActions: true,
    taskRouting: { mode: 'auto', plannerOnActError: true },
  });
</script>
<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async></script>

Form assistance

Guide users through complex multi-step forms with validation and auto-fill.

<script>
  (function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();
  rover('boot', {
    siteId: 'my-portal',
    publicKey: 'pk_site_your_public_key',
    allowedDomains: ['portal.example.com'],
    sessionScope: 'tab',
    taskRouting: { mode: 'planner' },
    checkpointing: { enabled: true, autoVisitorId: true },
  });
</script>
<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async></script>

Read-only support

Rover helps users find information and navigate, but doesn't take actions.

<script>
  (function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();
  rover('boot', {
    siteId: 'my-help',
    publicKey: 'pk_site_your_public_key',
    allowedDomains: ['help.example.com'],
    allowActions: false,
  });
</script>
<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async></script>

Strict host scope

Host-only install example for tightly controlled sites. Navigation behavior stays managed by Rover runtime.

<script>
  (function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();
  rover('boot', {
    siteId: 'secure-app',
    publicKey: 'pk_site_your_public_key',
    allowedDomains: ['app.example.com'],
    domainScopeMode: 'host_only',
    sessionScope: 'tab',
  });
</script>
<script
  src="https://rover.rtrvr.ai/embed.js?v=your_site_key_id"
  async></script>

A2W run examples

Use strict A2W POST when you can send JSON. Give URL-fetch chatbots a compact A2W GET link. Keep ?rover=..., ?rover_shortcut=..., and ?rover_playbook=... as visitor browser links.

Browser-first query param

Fastest way to make Rover run in the page UI on first-party rtrvr.ai. Other Rover installs expose ?rover= when AI launch is enabled for the site.

https://rtrvr.ai/?rover=get%20me%20the%20latest%20blog%20post

Create an A2W run

Machine path for any AI, CLI, or agent that needs progress and a final result back.

curl -X POST 'https://agent.rtrvr.ai/v2/a2w/runs' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "url": "https://rtrvr.ai",
    "prompt": "get me the latest blog post"
  }'

Cloud-hosted execution

Use cloud execution explicitly when the caller cannot open a real browser. The create call can return 202 before the run is finished; follow the returned links until terminal or input_required.

curl -X POST 'https://agent.rtrvr.ai/v2/a2w/runs' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Prefer: execution=cloud, wait=10' \
  -d '{
    "url": "https://rtrvr.ai",
    "prompt": "get me the latest blog post"
  }'

Chatbot GET execution

Use this when the caller can only fetch a URL. Rover opens the target in the hosted cloud browser and returns markdown with a self-contained poll link.

https://agent.rtrvr.ai/v2/a2w/runs?url=https%3A%2F%2Frtrvr.ai&prompt=get%20me%20the%20latest%20blog%20post&execution=cloud&wait=25&format=markdown

Create a run from a Rover deep link

If a discovered URL already contains rover or rover_shortcut, pass that full URL as url to GET /v2/a2w/runs.

https://agent.rtrvr.ai/v2/a2w/runs?url=https%3A%2F%2Fexample.com%2F%3Frover_shortcut%3Dcheckout_flow&execution=cloud&wait=25&format=markdown

Stream or continue the run

Use the canonical run URL for SSE, NDJSON, polling, continuation, and cancel.

# SSE
curl -N 'https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...' \
  -H 'Accept: text/event-stream'

# Continue input_required
curl -X POST 'https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{ "input": "Use the newest post from the blog index page." }'

# Cancel
curl -X DELETE 'https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_123?access=a2w_access_...' \
  -H 'Accept: application/json'

Cross-site handoff

Delegate a child task to another Rover-enabled site and keep one shared workflow lineage.

# Create the root run first
curl -X POST 'https://agent.rtrvr.ai/v2/a2w/runs' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "url": "https://x.com",
    "prompt": "Start checkout and hand off shipping selection when needed"
  }'

# Later, delegate from the parent run
curl -X POST 'https://agent.rtrvr.ai/v2/a2w/runs/a2w_run_parent/handoffs?access=a2w_access_parent' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "url": "https://y.com",
    "prompt": "Continue the checkout flow and return the shipping options.",
    "contextSummary": "User already selected product and entered address on x.com.",
    "expectedOutput": "Return the cheapest valid shipping option and ETA."
  }'

# Read the shared workflow
curl 'https://agent.rtrvr.ai/v2/a2w/workflows/a2w_wf_456?access=a2w_access_...' \
  -H 'Accept: application/json'

Node fetch

Self-contained hosted cloud example for agents running in Node 18+. On input_required it relays confirm/verify links to the human, posts sign-in links to auth-input, and answers ordinary questions — instead of giving up.

// askHuman(prompt) is your own human-in-the-loop prompt.
const createResponse = await fetch('https://agent.rtrvr.ai/v2/a2w/runs', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'accept': 'application/json',
    'prefer': 'execution=cloud, wait=10',
  },
  body: JSON.stringify({
    url: 'https://rtrvr.ai',
    prompt: 'get me the latest blog post',
  }),
});

const created = await createResponse.json();
const runUrl = created.run;
let run = created;

while (!['completed', 'failed', 'cancelled', 'expired'].includes(run.status)) {
  if (run.status === 'input_required') {
    const links = run.input?.links ?? {};
    if (links.confirm || links.verify) {
      // Payment/verification/sensitive-action gates: relay the link and poll.
      console.log(`Ask the human to open: ${links.confirm ?? links.verify}`);
    } else if (run.input?.reason === 'sign_in_link_required') {
      // Human pastes the magic link / OTP (secret: one-shot, never echoed).
      const value = await askHuman(run.authInput?.prompt ?? 'Paste the sign-in link or code:');
      const authInputUrl = new URL(runUrl);
      authInputUrl.pathname += '/auth-input';
      await fetch(authInputUrl, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ value }),
      });
    } else {
      // Ordinary question — or { answers: { key: value } } for multi-question parks.
      const answer = await askHuman(run.input?.message ?? 'Rover needs input:');
      await fetch(runUrl, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ input: answer }),
      });
    }
  }
  const runResponse = await fetch(runUrl, {
    headers: { accept: 'application/json', prefer: 'wait=10' },
  });
  run = await runResponse.json();
  console.log(run.status, run.result?.text ?? '');
}

if (run.status !== 'completed') {
  throw new Error(run.result?.error || `A2W run ended with ${run.status}`);
}

Python

Simple requests-based cloud execution loop that long-polls the returned run URL and handles input_required with the relay-or-continue pattern.

import requests

create = requests.post(
    "https://agent.rtrvr.ai/v2/a2w/runs",
    headers={
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Prefer": "execution=cloud, wait=10",
    },
    json={
        "url": "https://rtrvr.ai",
        "prompt": "get me the latest blog post",
    },
)
create.raise_for_status()
created = create.json()
run_url = created["run"]
payload = created

while payload["status"] not in {"completed", "failed", "cancelled", "expired"}:
    if payload["status"] == "input_required":
        req = payload.get("input") or {}
        links = req.get("links") or {}
        if links.get("confirm") or links.get("verify"):
            # Payment/verification/sensitive-action gates: relay the link and poll.
            print("Ask the human to open:", links.get("confirm") or links.get("verify"))
        elif req.get("reason") == "sign_in_link_required":
            # Human pastes the magic link / OTP (secret: one-shot, never echoed).
            value = input((payload.get("authInput") or {}).get("prompt") or "Paste the sign-in link or code: ")
            base, _, query = run_url.partition("?")
            requests.post(f"{base}/auth-input?{query}", json={"value": value}, timeout=30)
        else:
            # Ordinary question — or {"answers": {key: value}} for multi-question parks.
            answer = input(req.get("message") or "Rover needs input: ")
            requests.post(run_url, json={"input": answer}, timeout=30)
    current = requests.get(
        run_url,
        headers={"Accept": "application/json", "Prefer": "wait=10"},
        timeout=30,
    )
    current.raise_for_status()
    payload = current.json()
    print(payload["status"], payload.get("result", {}).get("text", ""))
if payload["status"] != "completed":
    raise RuntimeError(payload.get("result", {}).get("error") or f"A2W run ended with {payload['status']}")

Shell helper

Create a cloud A2W run and stream NDJSON events. Requires jq.

rover_run() {
  local url="$1"
  local prompt="$2"
  local created run_url

  created="$(curl -sS -X POST 'https://agent.rtrvr.ai/v2/a2w/runs' \
    -H 'Content-Type: application/json' \
    -H 'Accept: application/json' \
    -H 'Prefer: execution=cloud, wait=10' \
    -d "$(jq -nc --arg url "$url" --arg prompt "$prompt" '{url:$url,prompt:$prompt}')")" || return 1

  run_url="$(printf '%s' "$created" | jq -r '.run')"
  curl -sS "$run_url" -H 'Accept: application/x-ndjson'
}

rover_run "https://rtrvr.ai" "get me the latest blog post"

Need another browser pattern? Check Configuration for the supported SDK surface. For server calls, use the API Reference.

Quick StartInstall the embed and run your first task.API ReferencePublic browser, A2W, Connect AI, and analytics contracts.
← previousInstant Preview API