Smartflow Edge Chrome Extension
Transparent LLM API interception for browser-based AI workflows — no code changes required.
What it does
The Smartflow Edge Chrome Extension transparently intercepts outbound LLM API calls made from within Chrome web pages and routes them through your Smartflow proxy. Once a device is enrolled, every fetch() or XMLHttpRequest to a supported LLM provider is silently redirected — no code changes, no proxy configuration, and no manual API key management required.
The extension is built on Chrome Manifest V3 and uses the declarativeNetRequest (DNR) session rules API — the modern, privacy-preserving replacement for the deprecated webRequest API. Because rules are declarative and evaluated by the browser engine, the extension never reads request or response bodies.
Transparent Routing
LLM calls are redirected to Smartflow without modifying any application code. Works on any web app in the browser.
Virtual Key Injection
The extension injects a per-device virtual key (sk-sf-*). Real provider keys never leave the proxy.
Policy Enforcement
Devices belong to a policy group. Guardrails, budget limits, and routing policies apply automatically at the proxy.
Real-time Policy Push
Policy bundles are pushed via WebSocket. Changes made in the Smartflow dashboard propagate to enrolled devices instantly.
Use Cases
- Enforce AI usage policies for employees using browser-based AI coding assistants or playgrounds
- Centralize all LLM spend from web apps through Smartflow's budget & cost-tracking layer
- Apply guardrails (PII redaction, content filtering) to client-side LLM calls automatically
- Audit and log all LLM requests from internal web tools without touching their source code
- Lock down which AI models employees can use in the browser via routing policies
- Distribute API access to teams without giving out real provider keys
What is Intercepted (and What Isn't)
The extension intercepts client-side JavaScript API calls made from within browser tab contexts. This means it covers any web page whose JavaScript calls an LLM API directly from the browser.
Intercepted
- Direct
fetch('https://api.openai.com/...')orXMLHttpRequestcalls from web app JavaScript - Browser-based AI tools and sandboxes that call LLM APIs client-side
- API playground UIs (e.g. custom internal tools, OpenAI Playground clones)
- Internal company web apps that call LLM APIs from the frontend
- Any Jupyter-style notebook running in a browser tab that makes client-side LLM calls
Not Intercepted
- ChatGPT.com, Claude.ai, Gemini.google.com — these services make server-side API calls. The browser never issues a direct call to
api.openai.com, so there is nothing to redirect. - Native desktop apps (Cursor IDE, VS Code extensions, terminal tools) — these run outside the browser. Use IDE configuration instead.
- curl / CLI tools — configure via environment variables (
OPENAI_BASE_URL, etc.). - Server-side code running in Node.js, Python, etc. — these make calls from the server process, not the browser.
Architecture
headers: { Authorization: "Bearer sk-real-key..." }
})
/api/enterprise/policy-ws for live policy push/api/enterprise/devices/{id}/heartbeatx-api-key (sk-sf-*) budget & rate limit checksk-sf-* vkey from headers never forwarded to providersGemini · Cohere
Prerequisites
| Requirement | Details |
|---|---|
| Chrome / Chromium | Version 88 or later (MV3 support). Edge (Chromium-based) is also supported. |
| Smartflow Proxy | A running Smartflow instance reachable from the client machine (e.g. https://proxy.company.com). |
| Enrollment token or SSO | A one-time enrollment token generated by an admin, or an SSO provider configured in Smartflow (Azure AD, Google, Okta). |
| Admin access | Required only for generating enrollment tokens and managing devices. |
Installation (Sideload)
The Smartflow Edge extension is distributed as a .crx package or unpacked directory. It is not published to the Chrome Web Store — enterprise deployments use either sideloading or managed MDM deployment.
Obtain the extension package
Download the latest smartflow-edge-extension.zip from your Smartflow admin dashboard or ask your administrator for the unpacked extension directory.
Open Chrome Extensions
Navigate to chrome://extensions and enable Developer mode (toggle in the top-right corner).
Load unpacked
Click Load unpacked and select the extracted extension directory. The Smartflow Edge icon should appear in your toolbar.
Pin the extension
Click the puzzle-piece icon in the Chrome toolbar and pin Smartflow Edge so the popup is always accessible.
Token Enrollment
Token enrollment is the simplest method. An admin generates a one-time token and shares it with the user. The extension exchanges the token for a device credential and virtual key.
Admin generates a token
See Generating tokens for the API call. The token is single-use and expires after 24 hours by default.
Open the extension popup
Click the Smartflow Edge icon in the Chrome toolbar. You'll see an Enroll screen.
Enter the proxy URL and token
Enter your Smartflow proxy URL (e.g. https://proxy.company.com) and paste the enrollment token provided by your admin.
Click Enroll
The extension calls POST /api/enterprise/devices/token-enroll. On success, DNR session rules are installed and the popup shows your policy group and device ID.
What happens during enrollment
// POST /api/enterprise/devices/token-enroll
// Request body:
{
"enrollment_token": "enroll_abc123xyz",
"device_fingerprint": "chrome-ext-a1b2c3d4e5f6",
"device_name": "Jane's MacBook Chrome",
"platform": "chrome-extension"
}
// Response body (201 Created):
{
"device_id": "dev_7f8a9b2c",
"virtual_key": "sk-sf-7f8a9b2cXXXXXXXXXXXXXXXX",
"policy_group": "engineering",
"proxy_url": "https://proxy.company.com"
}
The extension stores the device_id, virtual_key, and proxy_url in chrome.storage.local and immediately installs the DNR session rules.
SSO Enrollment
SSO enrollment lets users authenticate with their existing corporate identity (Azure AD, Google Workspace, or Okta) to obtain device credentials. No admin-issued token is needed.
Open the extension popup and choose SSO
Click Sign in with SSO. The extension launches a chrome.identity.launchWebAuthFlow window to your configured identity provider.
Authenticate with your identity provider
Complete login in the popup window. The extension receives an id_token (JWT) from the provider.
SSO enroll is called automatically
The extension calls POST /api/enterprise/devices/sso-enroll with the id_token. Smartflow validates it against the configured IdP, maps the user to a policy group based on their directory group membership, and returns a device credential.
// POST /api/enterprise/devices/sso-enroll
// Request body:
{
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"device_fingerprint": "chrome-ext-a1b2c3d4e5f6",
"device_name": "Jane's MacBook Chrome",
"platform": "chrome-extension"
}
// Response body (201 Created):
{
"device_id": "dev_7f8a9b2c",
"virtual_key": "sk-sf-7f8a9b2cXXXXXXXXXXXXXXXX",
"policy_group": "engineering",
"proxy_url": "https://proxy.company.com"
}
How It Works: Redirect Rules
After enrollment, the service worker calls chrome.declarativeNetRequest.updateSessionRules() to install a set of redirect rules. These rules run entirely within the Chrome DNR engine — the extension background script never sees the request content.
The following LLM provider hosts are covered by redirect rules:
| Provider | Host |
|---|---|
| OpenAI | api.openai.com |
| Anthropic | api.anthropic.com |
| Google Gemini | generativelanguage.googleapis.com |
| Cohere | api.cohere.ai |
| Mistral AI | api.mistral.ai |
| Groq | api.groq.com |
| OpenRouter | openrouter.ai |
Each redirect rule rewrites the request URL so that the host and scheme are replaced with the Smartflow proxy URL while preserving the original path and query string. Resource types covered are fetch and xmlhttprequest.
// Example: what the DNR redirect rule looks like conceptually
{
id: 1001,
priority: 100,
action: {
type: "redirect",
redirect: {
transform: {
scheme: "https",
host: "proxy.company.com"
// path is preserved, e.g. /v1/chat/completions stays as-is
}
}
},
condition: {
urlFilter: "||api.openai.com/",
resourceTypes: ["fetch", "xmlhttprequest"]
}
}
declarativeNetRequest (DNR) session rules, not the deprecated webRequest API. Session rules are held in memory and cleared when the browser closes or the extension is disabled. They are reinstalled by the service worker on chrome.runtime.onStartup and chrome.runtime.onInstalled.
How It Works: Header Injection
After the redirect rule fires, the request arrives at the proxy with the original Authorization: Bearer <key> header still present. A second DNR rule — a modifyHeaders rule — runs on all requests matching the proxy's /v1/ path and performs three operations:
- Remove the
Authorizationheader — strips any key the web app may have sent. - Set
x-api-key: sk-sf-{vkey}— injects the device's virtual key so Smartflow can identify and authenticate the device. - Set
x-smartflow-device-id: {deviceId}— for per-device audit logging. - Set
x-smartflow-platform: chrome-extension— identifies the traffic source.
Authorization header due to security restrictions — but it can remove it. By removing the original key and injecting x-api-key, the extension ensures the web app's hardcoded or user-supplied API key is never forwarded to the proxy, preventing accidental key exposure and ensuring only enrolled-device virtual keys are accepted.
How It Works: Virtual Key Flow
Authorization removed
x-api-key: sk-sf-abc123
x-smartflow-device-id: dev_7f
2. Lookup device: dev_7f8a9b2c
3. Policy group: "engineering"
4. Check budget & guardrails
5. Strip sk-sf-abc123
6. Inject real OPENAI_API_KEY
(your actual OpenAI key, server-side only)
The virtual key (sk-sf-*) is scoped to the enrolled device. When a device is revoked, its virtual key is invalidated immediately — the real provider key is never compromised.
How It Works: Policy Enforcement
Every enrolled device belongs to a policy group (e.g. engineering, sales, contractors). Policy groups are configured in the Smartflow admin dashboard and define:
- Allowed models and providers
- Monthly budget caps (per-device and per-group)
- Guardrail profiles (PII detection, prompt injection detection, content filters)
- Routing rules (e.g. route GPT-4 requests to a cheaper model)
- Allowed hours of operation
Policy bundles are delivered to the service worker over a WebSocket connection at /api/enterprise/policy-ws. When an admin publishes a policy change in the dashboard, the updated bundle is pushed to all connected devices in real time. The service worker caches the bundle locally and applies it on the next request evaluation.
// Service worker: connect to policy WebSocket after enrollment
const ws = new WebSocket(
`wss://proxy.company.com/api/enterprise/policy-ws?device_id=${deviceId}&vkey=${virtualKey}`
);
ws.onmessage = (event) => {
const bundle = JSON.parse(event.data);
// bundle.policy_group, bundle.rules, bundle.budget_limits, ...
chrome.storage.local.set({ policyBundle: bundle });
};
Enterprise Deployment: Admin Token Generation
Admins generate one-time enrollment tokens and assign them to policy groups before distributing to users. Tokens expire after 24 hours and can only be used once.
# Generate a one-time enrollment token for the "engineering" policy group
curl -X POST https://proxy.company.com/api/enterprise/devices/enrollment-token \
-H "Authorization: Bearer $SF_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"policy_group": "engineering",
"label": "Jane Smith onboarding",
"expires_in_hours": 24
}'
// Response:
{
"token": "enroll_7xK9mQp2nRtLvZsW",
"policy_group": "engineering",
"expires_at": "2025-08-16T14:30:00Z",
"label": "Jane Smith onboarding"
}
Share the token value with the user. They enter it in the extension popup along with the proxy URL.
Enterprise Deployment: MDM Distribution
For large teams, use your MDM (Jamf, Intune, Workspace ONE) to force-install the extension and pre-configure it via Chrome's ExtensionInstallForcelist and managed storage policies.
Chrome policy (managed configuration JSON)
{
"ExtensionInstallForcelist": [
"smartflow-edge-extension-id;https://your-crx-update-url/update.xml"
],
"3rdparty": {
"extensions": {
"smartflow-edge-extension-id": {
"policy": {
"proxyUrl": "https://proxy.company.com",
"enrollmentToken": "enroll_MANAGED_TOKEN_HERE",
"policyGroup": "default",
"managedEnrollment": true
}
}
}
}
}
When managedEnrollment: true is set in managed storage, the extension auto-enrolls on first launch using the provided enrollmentToken without any user interaction.
Enterprise Deployment: Team Rollout
Recommended rollout sequence for teams:
- Configure policy groups in the Smartflow admin dashboard before issuing tokens.
- Pilot group — enroll 5–10 power users first, validate interception is working, confirm budget tracking.
- Generate batch tokens — use the admin API to generate one token per user (or one per policy group if using MDM managed tokens).
- Distribute via MDM for managed devices, or email tokens with enrollment instructions for BYOD.
- Verify via device list — use
GET /api/enterprise/devicesto confirm all expected devices are enrolled and sending heartbeats. - Set budget alerts in the dashboard to catch unexpected usage spikes early.
Enterprise Deployment: Managed Storage
The extension reads the following keys from chrome.storage.managed (set by your MDM/Chrome policy). Values set here take precedence over user-entered values and are read-only from the extension's perspective.
| Key | Type | Description |
|---|---|---|
proxyUrl | string | Smartflow proxy base URL. Locks the proxy URL so users cannot point the extension at a different server. |
enrollmentToken | string | One-time token for auto-enrollment on first launch. |
policyGroup | string | Overrides the policy group returned by the server (rarely needed). |
managedEnrollment | boolean | If true, auto-enrolls silently on first launch without showing the enrollment UI. |
disableUnenroll | boolean | If true, hides the unenroll button from the popup (prevents users from opting out). |
Admin API: Device Management
All device management endpoints require the Authorization: Bearer $SF_ADMIN_KEY header.
/api/enterprise/devices
List all enrolled devices. Returns device ID, name, platform, policy group, last heartbeat, and status.
curl https://proxy.company.com/api/enterprise/devices \
-H "Authorization: Bearer $SF_ADMIN_KEY"
{
"devices": [
{
"device_id": "dev_7f8a9b2c",
"device_name": "Jane's MacBook Chrome",
"platform": "chrome-extension",
"policy_group": "engineering",
"enrolled_at": "2025-08-15T10:22:00Z",
"last_heartbeat": "2025-08-15T14:01:33Z",
"status": "active"
}
],
"total": 1
}
/api/enterprise/devices/enrollment-token
Generate a one-time enrollment token for a policy group. See Generating tokens.
/api/enterprise/devices/{device_id}
Revoke a device. Invalidates its virtual key immediately. The next request from the device will receive a 401.
/api/enterprise/devices/{device_id}/heartbeat
Called by the extension service worker every 5 minutes to confirm the device is active. Updates last_heartbeat.
/api/enterprise/policy-bundle/{group}
Fetch the current policy bundle for a policy group. Useful for debugging policy issues.
Admin API: Generating Tokens
# Single token for a named user
curl -X POST https://proxy.company.com/api/enterprise/devices/enrollment-token \
-H "Authorization: Bearer $SF_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"policy_group": "engineering",
"label": "Jane Smith",
"expires_in_hours": 24
}'
# Batch: generate tokens for a list of users (shell loop)
for user in alice bob charlie; do
curl -s -X POST https://proxy.company.com/api/enterprise/devices/enrollment-token \
-H "Authorization: Bearer $SF_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d "{\"policy_group\": \"engineering\", \"label\": \"$user\"}" \
| jq -r '"'"'"$user: \(.token)'"'"'"
done
Admin API: Revoking Devices
# Revoke a specific device by ID
curl -X DELETE https://proxy.company.com/api/enterprise/devices/dev_7f8a9b2c \
-H "Authorization: Bearer $SF_ADMIN_KEY"
# Find and revoke all devices for a user (by name match)
curl -s https://proxy.company.com/api/enterprise/devices \
-H "Authorization: Bearer $SF_ADMIN_KEY" \
| jq -r '.devices[] | select(.device_name | test("Jane")) | .device_id' \
| while read id; do
curl -s -X DELETE "https://proxy.company.com/api/enterprise/devices/$id" \
-H "Authorization: Bearer $SF_ADMIN_KEY"
echo "Revoked: $id"
done
401 Unauthorized response, and the extension popup will show "Device revoked — please re-enroll."
Popup & Settings: Extension Popup
Click the Smartflow Edge icon in the Chrome toolbar to open the popup. The popup displays the current enrollment state and live status indicators.
| Field | Description |
|---|---|
| Status | Enrolled / Not enrolled / Revoked |
| Policy Group | The policy group assigned to this device (e.g. engineering) |
| Device ID | The unique device identifier (e.g. dev_7f8a9b2c) |
| Active DNR Rules | Number of declarativeNetRequest session rules currently installed (should be ≥ 2 when enrolled) |
| WebSocket | Connected / Disconnected — real-time policy push status |
| Last Seen | Timestamp of the last successful heartbeat to the proxy |
| Proxy URL | The configured Smartflow proxy endpoint |
Popup & Settings: Settings Page
Click Settings in the popup to open the full settings page (in a new tab). Available settings:
- Proxy URL — change the Smartflow proxy URL (disabled if set via managed storage)
- Device name — a human-readable label for this device visible in the admin dashboard
- Re-enroll — enroll with a new token without unenrolling first (replaces the existing credential)
- Debug mode — enables verbose logging in the service worker console (
chrome://serviceworker-internals) - Export diagnostic info — copies a JSON blob with device ID, policy group, DNR rule IDs, and WS status to clipboard for support
Popup & Settings: Unenroll
Clicking Unenroll in the popup:
- Removes all DNR session rules.
- Clears the virtual key and device ID from
chrome.storage.local. - Closes the WebSocket connection.
- Calls
DELETE /api/enterprise/devices/{device_id}to notify the proxy (best-effort — if offline, the device will be marked inactive after the next heartbeat timeout).
disableUnenroll: true is set via managed storage (MDM), the Unenroll button is hidden and disabled. Users on managed devices must contact their IT administrator to have the device revoked.
Troubleshooting: Common Issues
| Symptom | Likely cause | Fix |
|---|---|---|
| LLM calls still going to provider directly (not proxied) | DNR rules not installed or extension not enrolled | Open popup — check status is Enrolled and DNR rule count is ≥ 2. Re-enroll if needed. |
401 Unauthorized from proxy |
Device revoked or virtual key expired | Re-enroll with a new token. Check with admin whether device was revoked. |
| WebSocket shows Disconnected | Network issue or proxy restart | The service worker reconnects automatically with exponential backoff. Wait 30s; if still disconnected, reload the extension. |
| CORS errors in browser console | Web app's CORS check resolves against proxy URL instead of original origin | Ensure the Smartflow proxy sends appropriate CORS headers for your web app's origin. Configure allowed origins in the Smartflow admin. |
| Extension enrolled but no interception on a specific site | The site uses server-side LLM calls (e.g. ChatGPT.com) | Expected behavior — see What is intercepted. These calls cannot be intercepted by the extension. |
| Service worker stops after ~30 seconds of inactivity | Normal MV3 service worker lifecycle | The service worker wakes up automatically when a network request matches the DNR condition. DNR rules persist even when the worker is inactive. No action needed. |
Enrollment fails with 403 |
Token already used or expired | Ask admin to generate a new enrollment token. |
Troubleshooting: Testing Interception
To verify the extension is intercepting LLM calls, open the browser DevTools (F12) on any web page and run:
// In the browser console — this call SHOULD be intercepted and redirected
fetch("https://api.openai.com/v1/models")
.then(r => {
console.log("Response URL:", r.url);
// If intercepted: r.url will be on your proxy domain
// If NOT intercepted: r.url will be api.openai.com
return r.json();
})
.then(data => console.log(data))
.catch(err => console.error(err));
If the response URL shows your proxy domain (e.g. https://proxy.company.com/v1/models), interception is working. If you see api.openai.com in the URL or a CORS error directly from OpenAI, the extension rules are not active.
You can also observe the redirect directly in the Network tab of DevTools: look for a 307 (Internal Redirect) entry for the api.openai.com request, followed by the actual request to your proxy.
Troubleshooting: Checking DNR Rules
To inspect active declarativeNetRequest session rules from the service worker console:
- Go to
chrome://extensions - Find Smartflow Edge and click Service Worker (the hyperlink next to "Inspect views")
- In the DevTools console that opens, run:
// List all active session rules
chrome.declarativeNetRequest.getSessionRules(rules => {
console.table(rules.map(r => ({
id: r.id,
priority: r.priority,
action: r.action.type,
urlFilter: r.condition?.urlFilter
})));
});
You should see at minimum:
- One rule per LLM provider with
action: "redirect" - One rule with
action: "modifyHeaders"targeting the proxy's/v1/path
If the list is empty, the extension is not enrolled or the service worker encountered an error during rule installation. Check the service worker console for errors.
Security: What Data Is Sent
The Smartflow Edge extension sends the following data to the Smartflow proxy:
| Data | When sent | Purpose |
|---|---|---|
| Device fingerprint | Enrollment only | Stable identifier derived from browser characteristics. Never includes PII. |
| Device name | Enrollment only | Human-readable label shown in the admin dashboard. User-provided or auto-generated. |
Virtual key (sk-sf-*) | Every proxied LLM request (as x-api-key) | Authenticates the device at the proxy. Scoped to this device only. |
| Device ID | Every proxied LLM request (as x-smartflow-device-id) | Enables per-device audit logging and budget tracking. |
| Heartbeat | Every 5 minutes when enrolled | Keeps the device active in the admin dashboard. |
The extension does not read, store, or transmit:
- Request or response bodies (the DNR engine intercepts at the network layer, not application layer)
- Browsing history or URLs outside the LLM provider domains
- User credentials or session cookies
- Any content from web pages
Security: Privacy
The Chrome Manifest V3 declarativeNetRequest API was specifically designed to provide ad-blocking and request-modification capabilities without giving extensions access to request content. The extension's background service worker installs declarative rules that the browser engine evaluates natively — the extension never observes individual requests.
The only outbound connections the extension makes are:
- To the configured Smartflow proxy URL (for enrollment, heartbeat, and the policy WebSocket)
- Implicitly, all LLM API requests are now routed through the proxy — but this is by design and controlled by your organization
The extension does not contact any third-party services (no analytics, no telemetry to LangSmart's servers unless your proxy is hosted by LangSmart).
Security: Limitations
- No body inspection: The DNR API does not expose request/response bodies to the extension. Content inspection (PII redaction, prompt filtering) happens server-side at the Smartflow proxy.
- Service worker lifecycle: MV3 service workers are event-driven and can be terminated by Chrome after inactivity. DNR session rules are cleared on browser close. The service worker reinstalls rules on startup, but there is a brief window before the first LLM call after browser launch where rules may not yet be active.
- Extension can be disabled: Users with local admin rights can disable or uninstall the extension. Use MDM policies to prevent this on managed devices.
- Server-side calls not covered: Web apps that proxy their LLM calls through their own backend are not intercepted. Only direct client-side calls from browser JavaScript are covered.
- No TLS inspection: The redirect changes the destination host, but the extension cannot inspect the encrypted payload. All content guardrails run at the proxy after decryption.
- Smartflow IDE Configuration — for Cursor, VS Code, and other native AI tools
- Smartflow Platform Overview — architecture and component overview
- API Reference — full proxy and management API documentation