Rover in a Chrome Extension
Run Rover from your own Chrome extension on live sites such as LinkedIn — without installing the Rover npm package.
Use this when you want to test Rover from a Chrome extension you control, on sites you do not own. You package the Rover runtime files inside the extension and boot them with a config generated in Workspace.
Pick a Rover Config First
Start in Rover, then paste the generated values into your extension.
- 1.Open Workspace.
- 2.Create or select a Rover site.
- 3.Add the target domain in the site policy, for example
linkedin.com. - 4.Copy the extension/test config JSON from Workspace or Instant Preview.
For quick demos on arbitrary sites, use the reusable test config from Instant Preview. The config should contain values like:
{
"siteId": "your_site_id",
"publicKey": "pk_site_...",
"siteKeyId": "key_...",
"apiBase": "https://agent.rtrvr.ai",
"allowedDomains": ["linkedin.com"],
"domainScopeMode": "registrable_domain",
"openOnInit": true,
"allowActions": true
}Public keys only
UsepublicKey, not private secrets. Do not put admin tokens, API secrets, or service credentials in an extension.Why the Normal Script Tag Fails on Some Sites
Some sites block remote scripts with Content Security Policy. If your extension injects:
<script src="https://rover.rtrvr.ai/embed.js"></script>the page can reject it before Rover boots. Chrome Manifest V3 also expects extension-executed JavaScript to be packaged with the extension, not fetched as remote executable code.
The reliable extension pattern
- Download Rover runtime files at build time.
- Package them inside your extension.
- Inject packaged files with
chrome.scripting.executeScript. - Use Rover config from
rover.rtrvr.ai.
Minimal File Layout
my-rover-extension/
manifest.json
background.js
vendor/
rover-embed.js
worker.jsDownload the runtime files once while building your extension:
mkdir -p vendor
curl -L https://rover.rtrvr.ai/embed.js -o vendor/rover-embed.js
curl -L https://rover.rtrvr.ai/worker/worker.js -o vendor/worker.jsKeep those files checked into your extension repo or copied into your build output.
Manifest Example
This example is scoped to LinkedIn. Change host_permissions and matches for your target site.
{
"manifest_version": 3,
"name": "Rover Hackathon Extension",
"version": "0.1.0",
"description": "Run Rover from a packaged Chrome extension.",
"permissions": ["activeTab", "scripting", "storage", "tabs"],
"host_permissions": ["https://www.linkedin.com/*"],
"background": {
"service_worker": "background.js",
"type": "module"
},
"action": {
"default_title": "Open Rover"
},
"web_accessible_resources": [
{
"resources": ["vendor/worker.js"],
"matches": ["https://www.linkedin.com/*"]
}
]
}Background Script Example
Click the extension icon to inject Rover into the active tab.
const roverConfig = {
siteId: "your_site_id",
publicKey: "pk_site_...",
siteKeyId: "key_...",
apiBase: "https://agent.rtrvr.ai",
allowedDomains: ["linkedin.com"],
domainScopeMode: "registrable_domain",
openOnInit: true,
allowActions: true
};
chrome.action.onClicked.addListener(async tab => {
if (!tab.id || !tab.url) return;
const url = new URL(tab.url);
if (!url.hostname.endsWith("linkedin.com")) {
console.warn("Open a LinkedIn tab first.");
return;
}
const config = {
...roverConfig,
workerUrl: chrome.runtime.getURL("vendor/worker.js")
};
await chrome.scripting.executeScript({
target: { tabId: tab.id, allFrames: false },
world: "MAIN",
injectImmediately: true,
func: cfg => {
const rover = window.rover = window.rover || function () {
(rover.q = rover.q || []).push(arguments);
};
rover("boot", cfg);
},
args: [config]
});
await chrome.scripting.executeScript({
target: { tabId: tab.id, allFrames: false },
world: "MAIN",
injectImmediately: true,
files: ["vendor/rover-embed.js"]
});
});Use Isolated Content Scripts for Your Own UI
If you are adding your own extension UI or custom automation logic, keep most of it in an isolated content script. Use world: "MAIN" only for the small Rover boot bridge above.
Good split
background.js— extension button, permissions, network calls, storage.content.js— your overlay UI, DOM reads, click/type helpers.vendor/rover-embed.js— packaged Rover runtime.vendor/worker.js— packaged Rover worker.
This avoids page CSP problems and reduces conflicts with the website's JavaScript.
Common Fixes
- **CSP blocks
https://rover.rtrvr.ai/embed.js** — packageembed.jsasvendor/rover-embed.jsand inject the packaged file. - **Rover says the host is outside
allowedDomains** — go back to Workspace and add the domain.linkedin.comwithregistrable_domaincoverswww.linkedin.comand its subdomains. - Actions are disabled — make sure the Workspace key has Rover Embed enabled and your config has
allowActions: true. - Worker fails to load — set
workerUrl: chrome.runtime.getURL("vendor/worker.js")and includevendor/worker.jsunderweb_accessible_resources. - You need to test many unrelated sites — use the reusable wildcard config from Instant Preview. For production-like behavior, use an exact site config from Workspace.
Guardrails
- Only automate sites and accounts you are allowed to test.
- Respect target-site terms and rate limits.
- Keep public Rover keys public-only. Never ship private service credentials in an extension.
- Keep extension host permissions narrow when possible.