# Mouser + Component Search Engine (chip-fetcher playbook)

Mouser is a first-class playbook (NOT a fallback tier) — it covers the long tail of chips without dedicated mfr CAD pages. Read this when manufacturer-direct doesn't host CAD, OR when you need stock + pricing + ECAD in one go.

**Heartbeat every stage** per [`dashboard-flow.md`](dashboard-flow.md). The slide-CAPTCHA escalation is a particularly important moment to heartbeat: post `mouser slide-CAPTCHA — user help needed` so the dashboard surfaces the stuck state, then raise the scraping window with `browser_raise_os_window` and let the user drag the slider. Don't silently wait — the user should see on the dashboard that we're stuck on Mouser.

## Mouser CSE Library Loader — the universal fallback (don't miss this)

**Critical pattern:** when a manufacturer has no CSE portal of their own (`<mfr>.componentsearchengine.com` returns `DNS_PROBE_FINISHED_NXDOMAIN`) AND no UL deep-link AND nothing on the mfr's own site, **check Mouser CSE**.

Pattern: `https://mouser.componentsearchengine.com/entry_u_newDesign.php?mna=<MFR>&mpn=<MPN>&pna=mouser&vrq=multi&fmt=zip&o3=0&lang=en-GB`

Mouser proxies CSE for any chip in their catalog, not just chips whose manufacturer paid for a dedicated CSE portal. It hits the same SamacSys library backend, returns the same mfr-uploaded STEP/symbol/footprint, with the same single CSE login.

### ⚠ TWO traps that make `entry_u_newDesign.php` return NO partID (both verified 2026-06-23, TI ADCs)

The entry endpoint returns one of three pages. Only one has a `partID`:
- **"SamacSys Part Preview"** (len ~50KB) → contains `partID=<N>`. ✅ This is what you want.
- **"SamacSys Part Selector" / "Pick One"** (len ~8–21KB) → a disambiguation page, **no partID**. ❌

Two independent causes push you onto the no-partID pages:

1. **Use the ORDERABLE MPN, not the base part.** `mpn=ADS1263` → "Pick One" (the base part has many package variants, so CSE can't resolve one). `mpn=ADS1263IPWR` (orderable, with package suffix) → "Part Preview", partID 755745. **Always pass the orderable MPN with its package/reel suffix.** If you only have the base MPN, a distributor parametric lookup (`adom-mouser`/`adom-digikey`) gives the orderable variant, or try the common suffix (TSSOP `…IPWR`, QFN `…IRTER`).

2. **Do NOT append `&logo=&epm=0` to the entry URL.** Those two extra params silently flip CSE into the "Part Selector" page (no partID) **even for a valid orderable MPN**. Use the minimal param set above. This cost an afternoon of "no-partID" debugging — the bug was a malformed URL, not the chip or the browser.

### `chip-fetcher cse <MPN> --mfr "<Manufacturer>"` — the automated path (use this first)

Does the whole CSE chain in code: navigate clean → entry (orderable MPN) → partID → preview → zipForm → `ga/model.php` → import STEP+symbol+footprint. Retries the cold-call flake and keeps the dashboard "working on" bar live via a heartbeat ticker. Prefer it over hand-driving URLs.

### How the download works — same-origin XHR + Basic-auth header (the breakthrough)

CSE downloads are HTTP Basic Auth. Inline-cred URLs (`https://user:pass@host/…`) are REJECTED by `fetch()`, and a plain navigate pops Chrome's invisible Basic-auth dialog. **The robust technique: a same-origin `XMLHttpRequest` (from a tab already on `mouser.componentsearchengine.com`) with `xhr.setRequestHeader('Authorization','Basic '+btoa(user+':'+pass))`.** XHR (unlike fetch) accepts the Authorization header AND pulls the bytes into JS as an arraybuffer — so the zip never hits Chrome's download policy (which silently blocks the 2nd+ download). This is what `cse_fetch_zip` in `pup.rs` does. **Vault-auth works in ANY browser** — the auth is the XHR header from chip-fetcher's vault, not a browser cookie, so CSE runs fine in the user's Chrome even if their saved CSE login lives in Edge.

**Real example:** Espressif has no CSE portal. Probing `espressif.componentsearchengine.com` gave NXDOMAIN. UL portal `vendor.ultralibrarian.com/espressif/embedded` gave "No Access is defined." But Mouser's product page for ESP32-S3FN8 had an "ECAD Model" block linking to `mouser.componentsearchengine.com/...` — and that path served a complete bundle. Same trick worked for the ESP32-S3-WROOM-1-N4 module.

## ⚠ HARD RULE — CSE downloads need credentials embedded in the URL

**Before you click any "Download CAD Models" button on `*.componentsearchengine.com`, embed credentials inline.** The `/signin` form-login session cookie is USELESS for downloads — those endpoints issue a separate HTTP Basic Auth challenge that pops a native Chrome dialog **invisible to `browser_eval`**. Symptom: page lands on `chrome-error://chromewebdata/`, no file in Downloads, nothing in DOM to indicate why. (Verified painful 2026-05-04.)

```bash
# Pull creds from chip-fetcher's vault, urlencode, prepend to URL:
CRED=$(curl -s http://127.0.0.1:8786/api/credentials | python3 -c '
import sys,json,urllib.parse
d=json.load(sys.stdin)
c=next((x for x in d["credentials"] if "componentsearchengine" in x["host"]), None)
if c: print(f"{urllib.parse.quote(c[\"username\"],safe=\"\")}:{urllib.parse.quote(c[\"password\"],safe=\"\")}")
')
URL="https://${CRED}@mouser.componentsearchengine.com/preview_newDesign.php?o3=0&partID=<ID>&ev=0&fmt=zip&pna=Mouser"
adom-desktop browser_navigate "{\"sessionId\":\"chip-fetcher\",\"url\":\"$URL\"}"
```

Always urlencode the username (`@` → `%40`) and password — special chars are common in CSE passwords. **Use this pattern by default for every CSE click that triggers a download.** Full diagnostic, OS-keychain alternative, and the two-vault sync requirement: see [`credentials-and-logins.md`](credentials-and-logins.md) § HARD RULE — CSE downloads use HTTP Basic Auth.

**Discovery flow when you can't find CAD on a vendor's site:**
1. Use `adom-mouser part <MPN>` to get the Mouser product URL.
2. Navigate pup to that Mouser page.
3. Look for "ECAD Model" / "Library Loader" link/text on the product page.
4. Follow the CSE URL into `mouser.componentsearchengine.com/...` directly.
5. Drive the standard CSE Download flow (same as NXP CSE).

## Mouser — first-class playbook

**Mouser is the most important external resource chip-fetcher has after the manufacturer's own site.** It hosts the datasheet AND the ECAD bundle for nearly every chip in their catalog — and for the long tail of chips whose manufacturers don't publish CAD (Vishay passives, niche connectors, smaller-vendor SoCs), Mouser is the *only* source.

Direct user quote: *"mouser is a key resource here so we have to get into the skill how to work with their website."*

**What's on every Mouser product page (right sidebar):**

- **`Datasheet:`** block — a `<MPN> Datasheet (PDF)` link. Either Mouser-CDN-hosted (`https://www.mouser.com/datasheet/<…>.pdf`) or a redirect to the manufacturer's CDN. Behind Akamai's bot wall, so use the in-page `fetch()` pattern, not naked curl.
- **`ECAD Model:`** block — `PCB Symbol, Footprint & 3D Model` link. Routes into `mouser.componentsearchengine.com/...` and serves a `LIB_<MPN>.zip` with `.step` + `.kicad_sym` + `.kicad_mod`.
- Extra reference docs (app notes, training PDFs) listed as additional `<a href="*.pdf">` rows further down — scrape them all.

## Operating manual — Mouser

1. **Always go through pup Chrome** — never naked curl. Their CDN serves a 174 KB HTML denial page (`"Access to this page has been denied because we believe you are using automation tools"`) for any non-browser request.
2. **Use the auto-cookie-accept helper** on every navigation — Mouser's cookie banner blocks downstream clicks via z-index.
3. **Use in-page `fetch()` with `{credentials:"include"}`** to pull PDFs (Chrome session cookies + JA3 fingerprint pass Akamai). Decode base64 result back into the library. `cf-mouser-pdf-pull.sh` is the reference implementation.
4. **For ECAD bundles, drive the full CSE Download flow inside the pup window.** Mouser-hosted CSE shares the same single-sign-on cookie as `componentsearchengine.com` proper, so once the user is signed in there, every Mouser ECAD link works without re-auth.
5. **Mouser's Search API (`adom-mouser`) gives you the canonical product URL + `datasheet_url` field for every variant.** Walk all variants — the version with the populated `datasheet_url` is sometimes a different package SKU than the MPN you searched for.

## Mouser's slide-to-verify CAPTCHA

After ~5–10 automated requests in a session, Mouser shows a slide-to-verify CAPTCHA. **Stop and ask the user to drag the slider.** Use `browser_raise_os_window` + `browser_screenshot` to surface the obstacle, then say: *"Mouser hit me with a slide-CAPTCHA — please drag the slider on the pup window to clear it."* Resume the flow once the CAPTCHA clears.

**DO NOT pivot to a different source for ECAD bundles** — there is no other source for those. Direct user pushback: *"that was a good test case … you can't just abandon the website if that's the only way to get the step file and symbol/footprint and the datasheet."*

**Cooldown:** Mouser's verification token persists for 30+ minutes after the user clears the slider. Batch your Mouser fetches during that window so the user only ever has to slide once per session.

**Critical caveat:** Mouser's CDN is Akamai-protected and rejects naked `curl` (returns 200 OK with a "Access to this page has been denied" HTML page). To pull a Mouser-hosted PDF you must either (a) navigate pup Chrome there and trigger a download (file lands in `~/Downloads`, then `chip-fetcher pull`), or (b) use in-page `fetch()` via `browser_eval` with `credentials:"include"` — Chrome's session cookies pass Akamai's bot check and the response can be base64-encoded back through `awaitPromise:true`.

## When the slider hits — escalation order

1. **Try `browser_input_dispatch type:"move"` along the slider track followed by `type:"click"` at the right edge.** Trusted CDP input has `isTrusted: true` and may pass GeeTest's basic acceleration check; some Mouser slider variants accept it.
2. **Pivot to vendor-direct ONLY if Mouser is fungible for this chip's docs.** TI lit IDs, ST `/resource/`, NXP `/docs/` — there are non-Mouser paths for documentation. Not for ECAD bundles.
3. **For ECAD bundles, there is no fungible path.** Hand off via `desktop_open_url` to the user's native browser (real Chrome with browsing-history reputation, extensions, real input). They slide once, the CAPTCHA token persists 30+ minutes, then the rest of the session works through pup again.
4. **Don't silently abandon a website if it's the only path.**

## CSE auth — single login covers all `<mfr>.componentsearchengine.com` subdomains

Sign in once at `https://componentsearchengine.com/signin` with the user's email + password, and the cookie covers every per-vendor subdomain (nxp, mouser, etc.). On first visit to a subdomain, an HTTP **Basic Auth** popup may appear once — it accepts the same CSE creds. After that, downloads on subdomain pages work.

The CSE STEP files we get for NXP/Mouser CSE are **mfr-authored, FreeCAD-exported** with named PRODUCTs (`ASSEMBLY`, `Body`, `ThermalPin`, `PinsArrayLR`, `PinsArrayTB`) — same authoring pipeline as TI's Fusion-electronics exports. So CSE-distributed STEPs match UL-distributed STEPs in scene-graph quality.

**Filename pattern: CSE downloads land as `LIB_<MPN>.zip` (vs UL's `ul_<MPN>.zip`).** The `cf-autowatch.sh` script's filename match needs to handle both — regex is `^(ul_|LIB_).*\.zip$`.

## Chrome's "wants to Download multiple files" SILENT KILLER

When CSE fires a download, Chrome detects multiple downloads (symbol + footprint + 3D + datasheet often arrive as separate transfers) and shows an Allow/Block dialog the first time per origin per session. **Programmatic `.click()` and `MouseEvent` dispatch CANNOT click Allow** — it's a Chromium browser-chrome dialog, not a page element.

Symptom: download button "works" (no error, page doesn't change), but `~/Downloads` stays empty for minutes.

**Cure: pre-grant the `automatic_downloads` permission to `*.componentsearchengine.com` BEFORE opening the page.** Two known approaches:
- (a) use Chrome DevTools Protocol `Browser.grantPermissions` via pup before the first navigation
- (b) launch the pup profile with `--auto-open-devtools-for-tabs` plus a setup script that flips the permission

**Do NOT ask the user to click Allow** — see "chip-fetcher does ALL the clicking" rule. Cloudflare/CSE reject curl-with-cookies attempts (HTTP 403 → CF anti-bot challenge → redirect to `/register`), so Chrome inside pup is the only viable path. Once the permission is granted at profile-load, all CSE clicks in that session run unattended.

(`chip-fetcher/scripts/adom-desktop-chrome-permissions-prompt.md` is the open feature request to bake `automatic_downloads: granted` into every pup `browser_open_window` by default.)

## Anti-detection / browse as a real user

Even when you go through pup Chrome, sites still profile *behavior*. Burst-clicking 5 product pages in 30 seconds with no scrolling, no mouse-movement, no referrer chain looks like a bot regardless of TLS fingerprint. The remedies, applied always:

1. **Pre-warm with a referrer chain.** Don't deep-link straight to a product page. Visit `<vendor>.com/` first, wait 3 seconds, then click into a search → results → product. Anti-bot heuristics weight `Referer` chains heavily.
2. **Add 2–5 second random delays between navigations** (`sleep $((2 + RANDOM % 4))`).
3. **Scroll the page after load.** Even one `window.scrollTo({top:600,behavior:'smooth'})` then a pause then `scrollTo({top:1400})` shifts behavioral profile out of bot territory and triggers lazy-loaded content.
4. **Move the mouse.** A few `dispatchEvent(new MouseEvent('mousemove', {clientX:..., clientY:..., bubbles:true}))` calls between clicks help.
5. **Don't fetch the same domain in tight bursts.** When backfilling 14 chips, space them ≥4 seconds apart and reload one tab — don't open 14 tabs at once.
6. **Use a single persistent profile (`chip-fetcher`)** so cookies, fingerprint, and visit history accumulate.
7. **Detection escape valve:** if a site still 403s despite all of the above, slow down and ask the user to slide whatever CAPTCHA appears.

## Always browse as a real user

**Every PDF fetch goes through pup Chrome with a real session, not naked `curl`.** Vendor CDNs (Mouser/Akamai, Cloudflare, ST/Akamai, Nordic/Cloudflare, NXP/Cloudflare) actively profile traffic for "automation tools" — TLS fingerprint, header order, missing `sec-ch-ua`/`sec-fetch-*`, no JS execution, no cookies, no referrer chain.

**The rule: every fetch flows through pup.** Use one of these in priority order:

1. **In-page `fetch()` via `browser_eval`** with `{credentials:"include"}` and `awaitPromise:true`, base64-encoding the response body back through the JSON channel.
2. **Programmatic `<a>` click in the rendered page** — Chrome handles the download natively, file lands in `~/Downloads`, then `chip-fetcher pull <path>`.
3. **Naked `curl` ONLY for vendor-doc CDNs that are confirmed not behind a bot wall** — TI's `ti.com/lit/pdf/<id>` is one of the few that works. **Always validate by checking the first 4 bytes:**
   ```bash
   head -c 4 "$OUT" | grep -q "%PDF" || { echo "not a real PDF"; rm -f "$OUT"; }
   ```
   If the magic check fails, the vendor served a denial page. Re-route through pup.

**Never write a backfill script that does `curl ... > out.pdf` without the `%PDF` magic-byte gate.** A 174KB HTML denial page mis-stored as a `.pdf` is worse than a missing file.

Direct user pushback: *"make sure we never get errors like this. meaning always browse as a real user would."*
