# Browser extension connector (Agent Skill)

> A Chrome extension that connects a web service with no public API to your own app: it reads the site's own traffic from the signed-in browser, replays its auth only to that site, buffers offline and syncs through one polled endpoint.

Page: https://timerise.ai/skills/browser-extension-connector

Agent Skill `browser-extension-connector`: https://github.com/timerise-ai/browser-extension-connector. Category: AI & integrations. Runs on Chrome MV3; backend: Host app behind a two-endpoint contract, the service behind an adapter seam.

Latest release: v0.1.5 (2026-09-28).

Install: npx skills add timerise-ai/browser-extension-connector. Timerise builds it on a brief; the price comes from the brief.

Some of the services a business depends on have no API, no OAuth and no export. A marketplace seller panel, a carrier portal, a supplier's ordering site. The data is there, on screen, for a signed-in user. Getting it into your own system usually means someone retyping it, or a scraper that holds the user's password.

There is a third way. The user's browser already sees every response the site serves. A Chrome extension can read that traffic in the page's own context, replay the page's own auth headers for pulls and writes, and hand the result to your app. No password leaves the browser, and the site sees the same session it always did.

The hard part is not the tap. It is the runtime: a service worker Chrome evicts after thirty seconds, alarms that fire at most once a minute, a network that comes and goes. This skill gives a coding agent the connector built for that runtime, with a bounded offline buffer, one polled endpoint carrying records up and commands down, PIN pairing and diagnostics. The service itself sits behind an adapter seam, so one connector serves many sites.

Build a Chrome MV3 extension that acts on an external web service with no (or a limited) public API from inside the user's own signed-in browser session, observing the site's JSON traffic, replaying its auth headers for pulls and writes, buffering offline, and syncing with a host app through one polled endpoint that carries records up and commands down. Use when: (1) a product needs data out of, or actions into, a third-party site that offers no API, no OAuth and no export, and server-side scraping with the user's password is off the table, (2) an existing connector extension needs hardening: a service worker that dies, an alarm that never fires, a content script that shipped dead, records that go missing, commands marked failed without having run, (3) the user mentions: browser extension connector, chrome extension integration, no API, scrape from the logged-in session, MV3 service worker, content script MAIN world, tap fetch/XHR, replay auth headers, offline buffer, pairing PIN, "sync bookings from <site>", "publish to <site> without an API". Ships a compiled, tested runtime (tap, relay, worker, queue, pairing, diagnostics) and a vendor-neutral adapter seam; the host app's endpoints are a documented contract. Chrome MV3; host-agnostic. Not a per-service adapter; those are separate skills on top.

This skill was written by the engineer who has shipped this module. The earlier implementation it was audited against was a connector extension carrying one service's data into a host app, with an architecture note kept alongside it recording every incident. The templates hold the properties a connector has to hold: every response from the host handled the same way, so a command handed out on any post runs; every live relay port kept, so two open tabs are two ports; acks riding the next post, so a browser closing mid-command loses nothing; a buffer that is bounded, drops oldest and reports the drop; records validated one by one, so one bad record cannot wedge the channel; and a credential read only from the page's own requests, replayed only to the origin it came from, never persisted and never posted to the host. The suites and the build state each one, and [`references/provenance.md`](references/provenance.md) has the record.

What it builds:
- A MAIN-world tap on the page's own fetch and XHR
- Auth headers replayed only to their own origin
- A bounded offline buffer
- One polled endpoint carrying records up and commands down
- PIN pairing
- Diagnostics

When to use:
- Building or hardening an extension that connects a third-party site to your own app, where the site offers no partner API and handing over the user's password is not acceptable. The service is the seam; this skill is the infrastructure under any service adapter.

When not to use:
- **The site has an API or OAuth.** Use it; this is a workaround with real costs.
- **Server-side scraping with stored credentials.** Different threat model; not covered.
- **A one-off data export**: a script in DevTools is cheaper than an extension.
- **Writing a specific service's adapter**: a separate skill built on this one ([adapter-seam.md](references/adapter-seam.md) says what it must provide).
- **The host app's routes and schema**: described as a contract here, built in the host's own idiom ([server-contract.md](references/server-contract.md)).
- **Recording how employees work, with their consent**: the [`ecommerce-process-mining`](https://github.com/timerise-ai/ecommerce-process-mining) skill. This one moves a service's data, not a record of the work.

Non-negotiables:
- Never create the alarm unconditionally at startup. `chrome.alarms.create` replaces and restarts a same-named alarm, so a worker that is revived often pushes its own next fire away and never polls. Check `alarms.get` first, and poll immediately on bootstrap.
- Never fall back to a worker-side fetch when no service tab is open. The worker holds no session with the service, so a login page comes back, parses as zero rows, and looks exactly like a finished pull. Refusing is what makes the failure visible on the connection card.
- Never keep one "current port". Two open tabs are two relay ports, and closing the newer one must not orphan the older. `PortRegistry` keeps them all and `ports.test.ts` pins the rule.
- Never acknowledge a command on the same post that ran it. Acks ride the next post, so a browser that closes in between lets the lease expire and the command comes back instead of being lost. Three cases in `engine.test.ts` cover the ack path, including a post that gets no answer.
- Never validate a batch as a whole on the host. One bad record must cost one record, named in `rejected`; a batch-level `400` keeps the whole buffer re-posting forever while the card still says connected.
- Never write into the service until the write path is verified live , and never delete by anything but the id the service returned. `writeVerified` gates every writing command, and a create that returns no id throws rather than leaving something only a human can remove.

Not this:
- A service with a partner API, OAuth or an export: That API. A connector is a workaround with real costs, and this skill says so before it starts
- Server-side scraping with the user's stored password: Nothing here. It is a different threat model, it works from anywhere forever, and it usually breaks the service's terms
- A one-off data export: A script pasted into DevTools, which is cheaper than an extension and stops existing afterwards
- One service's parsers, endpoints and quirks: An adapter skill on top of this one, written against `references/adapter-seam.md`
- The host's routes, staging tables, merge queues and console UI: The host's own idiom, to the contract in `references/server-contract.md` and the operator surface in `references/operations.md`
- Recording how employees work, for SOPs or automation scoping: The sibling [`ecommerce-process-mining`](https://github.com/timerise-ai/ecommerce-process-mining) skill, which captures consented DOM events from the tools staff already use; this one carries a service's data, not a record of the work
- Pairing and running unattended screens in a venue: [`digital-signage`](https://github.com/timerise-ai/digital-signage), which pairs displays by PIN and plays to them

Requirements:
- **Chrome 120 or newer.** `world: "MAIN"` in a declared content script is the whole basis of the tap.
- **Node with `esbuild`**, plus `typescript` and `vitest` for the checks. Nothing else: the build is five bundles in two formats and a zip written with `node:zlib`.
- **A host app that answers two endpoints**, pair and sync, to [`references/server-contract.md`](references/server-contract.md). Anything that can serve JSON will do.
- **One adapter per service**, written against [`references/adapter-seam.md`](references/adapter-seam.md) as its own skill. The tree builds and boots with the shipped stub, and syncs nothing until an adapter is wired.

What to tell your agent:
- Build a Chrome extension that pulls our orders from a supplier portal with no API, from the user's signed-in session, and sends them to our app.
- Our extension's service worker dies and records go missing. Make the sync reliable with an offline buffer and a single polled endpoint.
- Pair the extension with a user's account in our app using a PIN, instead of asking for their password.

Agent eval results (newest per agent and prompt):
- Gemini CLI (gemini-3.8-flash) on v0.1.5, 2026-09-28: pass (Chrome MV3)
- Codex CLI (gpt-6-astra) on v0.1.5, 2026-09-28: pass (Chrome MV3)
- Claude Code (claude-opus-5-5) on v0.1.5, 2026-09-28: pass (Chrome MV3)

Recent releases:
- v0.1.5 (2026-09-28): Wording release, from scoring the prompt-1 agent eval runs against 0.1.4. The templates are unchanged.
- v0.1.4 (2026-09-28): Fix release, from scoring the prompt-1 agent eval runs against 0.1.3. Connectors built from an earlier version should copy in src/inject/net-tap.ts, src/background/ports.ts, src/background/queue.ts, src/background/engine.ts and src/background/index.ts, and the three test files that pin them.
- v0.1.3 (2026-09-28): Documentation release. The skill content is unchanged from 0.1.2.
