Web browser automation that reads your own browser before it drives anyone else's
Every top result for this keyword is about how to drive a browser: Selenium, Playwright, Puppeteer, Firecrawl, Browserless, Cloudflare Browser Run. None of them talk about the part that actually makes "fill this form" useful, which is knowing who you are. Fazm runs a local Swift extractor on first launch, pulls your Chrome autofill, saved logins, history, and bookmarks into a single SQLite at ~/ai-browser-profile/memories.db, and exposes it to the agent as query_browser_profile. The agent looks up your real values first, then drives the tab.
THE MISSING HALF OF THE SERP
Driving is solved. Identity is not.
Playwright has been public for six years. Puppeteer, nine. Selenium, sixteen. The pieces of a browser you can drive from code are, at this point, a shopping list: navigate, click, type, fill, snapshot, screenshot. Every page on the first SERP for "web browser automation" iterates on the same list with new wrappers. The part that has not moved is the identity slot. Every automation is still a function where the caller has to supply "email address," "phone number," and "shipping address" by hand.
Fazm moves that. A local Swift package pulls your existing Chrome autofill into a tagged SQLite database before the browser leg ever runs, and the agent consults it the way a human consults their own memory. The fill call ends up pre-populated. You never typed.
THE ANCHOR
One SQLite file. Nine tags. The agent reads it first.
The extractor ships as a Swift package called ai-browser-profile-swift-light. You can find it in Fazm's Desktop/Package.swift as a dependency on github.com/m13v/ai-browser-profile-swift-light, pinned at 0.1.0. When Fazm launches for the first time, or any time a profile query returns empty, it runs the extractor, which reads the per-profile SQLite files Chrome maintains (autofill, logins, history, top sites), normalizes the values, tags them, and writes the result to ~/ai-browser-profile/memories.db.
That is the whole storage layer. One table, two indexes, nine legal values for the tag column. The agent never sees this file directly. It calls the MCP tool query_browser_profile(query, tags?), which is declared in acp-bridge/src/fazm-tools-stdio.ts at line 363 and registered alongside ten other fazm_tools on every startup. Every field on a form maps to a tag, and the tag narrows the return set to the right bucket of your memory.
DATA FLOW
Where the profile comes from, where it goes
Your Chrome -> memories.db -> agent -> the form
The hub is a single SQLite file. The sources are four SQLite (and one JSON) files that already exist on your Mac today, created by Chrome itself. The destinations are MCP tool calls the agent issues in the order they would naturally chain: read the profile, pick a field, fill it, let the user override if they want.
What "automate this form" looks like, with and without
Same task, two substrates. The difference is about 0 tagged value lookups that either happen silently before the browser leg runs, or that you end up doing by hand for every request.
Filling a signup form for a new SaaS tool
The script or agent has no memory of you. Every call that takes identity input either has to be parameterized by the caller (Selenium, Playwright) or the model has to hallucinate plausible values (vision-based agents). Either way, the actual form never gets submitted with values you would have typed yourself.
- Email: supplied manually by the caller every run
- Phone: supplied manually or left blank
- Address: typed in at prompt time, per task
- Card: never stored, so the run stalls at checkout
- Resume URL, LinkedIn, GitHub: the model guesses
ON FIRST LAUNCH
What extract_browser_profile actually does
Local extraction, 1-2 seconds
Locate Chrome profile dir
~/Library/Application Support/Google/Chrome/Default
Read four SQLite files
Web Data, Login Data, History, Bookmarks
Join by semantic key
same email, same phone, same address
Score by frequency
freq column ranks top autofills first
Write memories.db
one row per tagged fact, local only
Everything here is Swift code that ships inside Fazm.app. The extractor is imported in Desktop/Package.swift as BrowserProfileLight and wired into onboarding at Desktop/Sources/OnboardingChatView.swift line 1390. There is no Python environment, no pip install, no network round trip. You open the app, accept the Accessibility permission, and the profile is ready by the time the first chat turn starts.
A REAL RUN
What the tool log looks like when the agent fills a checkout
Every web browser automation tool, placed by what it does with identity
Selenium / Playwright / Puppeteer
Script-based browser drivers. No profile, no memory. Identity is a function argument you supply from a fixture file or an env var on every run.
Browserless / Firecrawl / Cloudflare Browser Run
Cloud headless Chromium behind an API. Clean container per request, so nothing carries over. Identity is irrelevant because the model cannot even see your saved data.
Browser-Use / Nanobrowser
Vision-based agents that OCR screenshots of the page. Can observe a 'Email' label next to an input, but cannot know what to type unless you tell them in the prompt.
Fazm
Reads your Chrome's own SQLite into a local tagged database, then asks the agent to consult it before any fill. Same values you would have typed, with none of the typing.
Bardeen / Automa / UI.Vision
Record-and-replay extensions. Identity is stored inside the recording, one value per flow. Reusing the value in a new flow means re-recording.
Identity-first vs. the shopping-list approach to web browser automation
Two categories that sound like they compete but actually solve different halves of the same problem.
| Feature | Driving-only tool | Fazm |
|---|---|---|
| Reads your existing browser profile | No, starts from zero | Yes, via local Swift extractor |
| Knows your real email without being told | No, caller supplies | Yes, tag: contact_info |
| Knows your card at checkout | No, stops at payment step | Yes, tag: payment |
| Where the profile is stored | Nowhere, or in test fixtures | ~/ai-browser-profile/memories.db (local SQLite) |
| Refresh cadence | Manual, every script update | Auto, when older than 24h |
| Editable by the user | No, embedded in code | Yes, edit_browser_profile tool |
| Scope beyond the browser tab | No, browser only | Yes, same tool called from native app automations |
| Cloud round trips for profile data | N/A, no profile layer | Zero |
Documented upper bound for extract_browser_profile in acp-bridge/src/fazm-tools-stdio.ts line 342. The lower bound is about 1 second on a warm machine.
identity, contact_info, account, tool, address, payment, contact, work, knowledge. The full legal set the agent can pass to the tags parameter.
After 24 hours, the next query triggers an automatic re-extraction. The user never has to remember to refresh.
“The web browser automation loop that every script-based tool accepts as normal (fetch the page, ask the user what to type, submit) collapses to two steps when the agent has already read your Chrome: fetch the page, fill it. The identity question is answered before it is asked.”
Fazm runtime, fazm-tools-stdio.ts line 363
What the extractor actually reads on first launch
- Chrome autofill entries (names, emails, phones, addresses)
- Saved logins and associated usernames
- Recent history (to score which sites you use most)
- Bookmarks (to infer tools and companies)
- Top-visited domains per profile
- Payment methods stored in Chrome Autofill
- No passwords (Chrome's encrypted credentials stay encrypted)
- No cloud sync, no telemetry, no network call
THE TAG SET
Nine tags that make the profile queryable
Each tag is a narrow slice of what the extractor found. A checkout needs payment plus address. A signup needs contact_info plus identity. A job application needs work plus knowledge. The agent picks the tags by looking at the form it just snapshotted, then issues one query_browser_profile call per slice.
HOW TO VERIFY ANY OF THIS
The three places in the source that make this checkable
Package.swift line 18
The Swift package dependency: .package(url: github.com/m13v/ai-browser-profile-swift-light, from: 0.1.0). This is where the extractor enters the Fazm build graph.
acp-bridge/src/fazm-tools-stdio.ts lines 341-373
The three tool declarations: extract_browser_profile, edit_browser_profile, query_browser_profile. The human-readable descriptions on each tool are the prompts the agent reads to decide when to call them.
Desktop/Sources/BundledSkills/ai-browser-profile.skill.md
The bundled skill file the agent loads at startup. It contains the lookup table that maps natural-language phrases ('what's my email', 'what's my address') to tag-scoped queries against the profile DB.
Want to see query_browser_profile run on your own Chrome?
Twenty minutes with the founder. We extract the profile live, show the DB, and run an end-to-end form fill from your real autofill data.
Book a call →Frequently asked questions
What does Fazm's web browser automation have that a Selenium or Playwright script does not?
An identity layer. Before the agent drives a single tab, Fazm runs a local Swift extractor (ai-browser-profile-swift-light, v0.1.0, declared at Desktop/Package.swift line 18) that reads your Chrome's autofill, saved logins, history, and bookmarks out of the browser's SQLite files, builds a structured profile of you, and writes it to ~/ai-browser-profile/memories.db. That profile is then addressable at runtime via a tool called query_browser_profile. When the agent hits a signup form, a checkout, or a support request, it pulls your real email, real phone, real address, real card, and real saved accounts from that database instead of hallucinating placeholders. Selenium has no concept of you. Playwright has no concept of you. Both drive a fresh browser with a blank profile, and you are the one who has to hand-feed them every value.
Where is this profile stored and what is in it?
On your Mac, at ~/ai-browser-profile/memories.db. It is a local SQLite file. The extraction takes 1 to 2 seconds and is re-run automatically whenever the agent's query hits a profile that is missing, stale (older than 24 hours), or incomplete. The schema has nine tag filters that the agent can narrow by: identity, contact_info, account, tool, address, payment, contact, work, and knowledge. You can list the raw tags in the MCP tool registry at acp-bridge/src/fazm-tools-stdio.ts line 369. Nothing in that database ever leaves the machine. There is no cloud sync. There is no telemetry for the contents.
Why does a web browser automation tool need to read the browser, not just drive it?
Because most real automations involve typing information the agent does not start with. 'Sign me up for this newsletter' needs your email. 'Book the meeting room' needs your calendar identity. 'Request a refund' needs your order ID and your address. 'Apply to this job posting' needs your phone, resume URL, and work history. A driving-only tool either has to ask you for each one (destroying the whole value proposition), or it has to invent plausible-looking fake values and send them (destroying trust). Fazm does neither; it pulls the value you have already saved into Chrome and uses that.
Does this work if I have never used autofill in Chrome?
Partially. If Chrome has zero autofill records, zero saved logins, and an empty history, query_browser_profile returns nothing meaningful and the agent will have to ask you. The realistic case is different: anyone who has used Chrome as their primary browser for a few months has a rich autofill set by accident, because Chrome's Payment Autofill, Address Autofill, and Password Manager are on by default. The extractor reads what is already there. There is no 'fill in this wizard' step. If you want to override or remove a specific entry after the fact, the agent can call edit_browser_profile (fazm-tools-stdio.ts line 350) with action: delete or action: update.
Is the extraction safe? What about Chrome's encrypted login data?
Two things. First, the extractor runs entirely locally. It links into your Fazm.app process as a Swift package dependency (ai-browser-profile-swift-light on GitHub at m13v/ai-browser-profile-swift-light, pulled from your Package.swift); there is no server involved. Second, it reads what the OS will give it using standard Chrome storage locations. Encrypted login credentials that require Chrome's own key to decrypt are not decrypted; only the metadata and the fields Chrome stores in the clear (autofill entries, history, bookmarks, non-password credentials) are surfaced. The profile database never contains a password. You can confirm this by opening ~/ai-browser-profile/memories.db in any SQLite browser and grepping for 'password'.
Who actually calls query_browser_profile and when?
The local agent, automatically, whenever the task requires personal context. The bundled skill file at Desktop/Sources/BundledSkills/ai-browser-profile.skill.md tells the model exactly which phrases trigger a query: 'what's my email', 'what accounts do I have', 'what tools do I use', 'find contact X', 'what's my home address', 'what card do I use'. The model is also free to call it unprompted when it notices the page it has just snapshotted contains a form with a 'Phone number' field, an 'Email' field, or a 'Shipping address' block. The first time any query returns empty, the agent silently runs extract_browser_profile to refill the database, then retries.
Is this just 'reading LocalStorage'? Why does it matter that it is SQLite?
Chrome stores profile-scale structured data (autofill, history, logins, top sites) in per-profile SQLite files, not LocalStorage. LocalStorage is per-origin key-value, which is useless for 'what is my phone number'. The extractor reads those real SQLite files, joins across them, normalizes the values (so 'mdiakonov@gmail.com' and 'm.diakonov@gmail.com' do not both show up as separate primary emails), scores them by frequency, and writes a consolidated record keyed on semantic role. Addressable by a tag like payment or address, not by 'row 4124 of cookies.db'. That normalization is why query_browser_profile returns a useful answer instead of raw dumps.
Does this replace Playwright or sit next to it?
Next to it, and it calls it. Fazm's runtime registers both as peer MCP servers in the same Agent Control Protocol bridge. query_browser_profile is one of the fazm_tools MCP tools (acp-bridge/src/fazm-tools-stdio.ts, alongside ten other helper tools). The browser automation leg is Playwright, attached to your real Chrome via a Chrome Web Store extension (ID mmlmfjhmonkocbjadbfplnigmagldckm, see Desktop/Sources/BrowserExtensionSetup.swift line 220). The agent first calls query_browser_profile to get the values it needs, then calls browser_snapshot to see the form, then calls browser_fill_form with the ref of each field and the value from the profile. One agent, two MCP servers, one continuous tool call chain.
What happens if Chrome is not my primary browser? Arc, Brave, Edge?
The extractor is Chrome-first because Chrome has the most consistent SQLite schema across versions, and because the majority of Fazm users run Chrome. Brave and Edge use a Chromium profile layout that works in practice but has not been formally tested. Arc is a special case because it uses its own profile directory and sidebar UI; the extractor can still find the SQLite, but field coverage is lower. Safari is not currently supported (it uses a different storage engine under a stricter sandbox). If you want to see what was actually extracted, the profile markdown is surfaced inside Fazm's onboarding chat view (Desktop/Sources/OnboardingChatView.swift line 1390 is where extract_browser_profile is wired into the onboarding flow).
How does this change what 'web browser automation' means, compared to the SERP definitions?
The SERP definition is 'a library or service that drives a browser through scripts or an API.' That framing puts the automation author on one side and the browser on the other, with a forever-empty identity slot in the middle that the author has to fill by hand in every test case. Fazm's definition is: the browser is already where you live, most of your identity is already in it, the agent reads that first, then drives it. The web browser becomes a source of truth for 'who the user is,' not just a dumb surface the automation pokes at. That is why reading the profile changes the shape of every subsequent tool call, not just one.
Related reading
Automation web browser: the snapshot-first, real-Chrome agent model
Why clicking by accessibility ref beats clicking by pixel, and how Fazm continues into Mail, Finder, and WhatsApp from the same message.
Browser automation tool: Fazm ships the browser as one of five peer tools
The browser is not the whole product. A tour of the five built-in MCP servers Fazm registers at runtime.
Browser automation extension: the Chrome Web Store bridge Fazm uses
How the Playwright MCP Bridge extension attaches to your real Chrome, and why that matters for bot detection and 2FA state.