Browser-as-Middleware: a Zero-Infra Integration

I shipped an app gluing 2 services: one behind-VPND legacy tool and a b2b a SaaS product without storing data or running an integration backend.

"Zero-infra" here doesn't mean serverless.
It means: no app server, no database, no service identity to provision.
The runtime is the user's browser session. The only server involved was an internal update channel for distributing the extension.

And it can also do shareable URI for deeplinks.

Why This Was Needed

Managers and scheduling teams had to reconcile scheduling/attendance with payroll and billing (daily for ops, monthly/quarterly for audits). The cost wasn't just time: role/rate mismatches but missing billables, and contract leakage left real money on the table.

This wasn't big data. It didn't require a complex Spark solution.
What it required was to highlight, contextualize and make easy to action maybe 300-400 data points per week on average per team lead and service manager.

Constraints (Why a Normal Backend Didn't Happen)

Two sources of truth: a SaaS product (GraphQL) + an internal VPN-only platform with no API.
Direct database access was a hard no.
Proper server-side integration required corporate OAuth/identity approvals that a long global process for our local office.
Auth was the real blocker: the service identity problem was harder than the data problem.
Persisting data would have increased governance/security scope for a workflow that only needed "today's truth".

The Pivot

I prototyped the workflow as if I had clean API/DB access in case the projecrt was ever greenlit.

Then for faster iteration and have real data, I started hooking up the backend of the app to my own browser's by sharing cookies.

Then it clicked: "too bad not every user can do this"... unless the integration runs inside a Chrome extension. Users were already authenticated to both systems, so I reused the browser session as the integration surface.

Architecture At A Glance

A Chrome extension (made with Plasmo here) gets authenticated access to both services using the user's sessions.

  • A React-based SPA (packaged as a PWA) renders a unified reconciliation workflow.
  • Data: No database: data is fetched fresh, normalized, joined, and diffed in-memory.
  • SaaS side: GraphQL calls via a lightweight typed wrapper (no heavy client in the bundle).
  • legacy side: session-driven requests; if expired, the extension opens a tab, waits for re-auth, then resumes.

What I Built

  • Plasmo/react/typescript chrome extension: background + content scripts with typed message contracts between contexts.
  • Session-aware fetch: cookie reuse, expiry detection, and guided "reauth then resume".
  • Lightweight type-safe GraphQL abstraction designed to not over-fetch from the SaaS
  • Normalization + reconciliation pipeline: map roles/rates/projects, join records, compute mismatches.
  • Action layer: one-click "post back" / trigger scripts so fixes happen from the diff view.
  • Cross-app context injection: show Service A context inside Service B pages (and vice versa).
  • Deep links without a real domain: capture URL patterns and route them into a dedicated extension window (pseudo-URLs that behave like shareable links).

Hard Parts (And How I Approached Them)

  • Session lifecycle as a state machine (valid -> expired -> reauth -> resume) with user-visible guardrails.
  • Reliability: safe retries/backoff + explicit UI states for VPN/auth/rate-limit failure modes.
  • Data correctness: deterministic normalization and mismatch detection applying rules that were in place when the workflow was manual
  • Performance: parallel fetch + incremental rendering + TTL caching tuned for "fresh small data".
  • Security: least-privilege permissions, origin checks, sanitize cross-context payloads, store nothing by default.

Tradeoffs

Data ownership

  • No persistence limits historical analytics.
  • Benefit: low governance overhead and no data custody.

Security

  • The code ships to clients .
  • No worse that bundling JS from the server to the client
  • but something to keep in mind as the dev version of the chromre sits on user's hard drive
  • make sure to keep nothing problematic in the shipped bundle

Outcome + What I'd Do Next

  • Minimal update service exists only to distribute/auto-update the extension. If not wanting to rely on google and its enterprise services for this, it remains the biggest pain point. Maybe a chrome extension can update itself without going through the store.
  • Saved 100+ hours/week across managers and improved revenue capture by a double-digit percentage.