Detecting the AI Stack

Can you tell if a company uses Anthropic or OpenAI?

Sometimes. You can identify Anthropic or OpenAI from the outside when a site ships provider SDK code, a model ID string, or a direct browser call, but most apps proxy the model through their own backend, which hides it. Bassethound fingerprints the visible providers in the AI-readiness layer of its five-layer dossier and reports the proxied blind spots as gaps, in one keyless call.

Best move: read what ships to the browser (bundled SDK code, model ID strings, network calls), not the “powered by AI” copy on the homepage.

Why it works: the provider only leaks when client code references it. When the app hides the call behind its own backend, the honest answer is that you cannot see it, and a good detector says so.

Key takeaways

  • You can sometimes identify the provider from the outside, but only when client-side code, a model ID string, or a direct browser call leaks it.
  • Most production apps proxy the LLM call through their own backend, so api.anthropic.com and api.openai.com never appear in the browser at all.
  • Client-bundled SDKs (the Anthropic SDK, the OpenAI SDK, and Vercel AI SDK provider packages) are the strongest provider tell that survives minification.
  • AI chat widgets like Intercom Fin and Sierra prove a company ships AI but abstract which model provider runs underneath.
  • Bassethound fingerprints the visible providers in the AI-readiness layer and reports proxied or server-side blind spots as gaps rather than inventing a match.

What reveals Anthropic versus OpenAI from outside?

Client-side evidence, ranked by confidence. The strongest tell is provider SDK code in a bundled script: an Anthropic SDK import, the OpenAI SDK, or a Vercel AI SDK provider package. The second is a model ID string that survives minification, something shaped like a Claude or GPT identifier sitting in the JavaScript. The third is a network call the browser makes directly to a provider host, which is rare because it exposes keys, but it happens on prototypes and internal tools. The fourth is response shape and streaming format, which differs between providers and can corroborate a weaker signal.

Any one of these is a lead. Two that agree (an SDK import plus a matching model string, say) is a confident match. None of them requires a login, and none depends on what the marketing page claims. That is the point. A company can write “built on frontier models” and run nothing, or write nothing and ship a full RAG stack. Bassethound reads the code path, so the answer tracks the engineering, not the copy. When the signals live only in a client-rendered bundle, detection needs JavaScript rendering to surface them.

Why is the provider usually invisible?

Because the correct architecture hides it. A well-built app keeps its provider key server-side and exposes something like /api/chat on its own domain. The browser talks to that route, the backend talks to Anthropic or OpenAI, and the provider hostname never enters the network tab. From the outside you see the company’s own endpoint and a streaming response, not the model behind it.

This is not an edge case. It is the default for anything past a weekend prototype, because putting a provider key in the browser is a security mistake. So the base rate of “provider fully visible from outside” is low, and it drops as an app matures. That has a blunt consequence: absence of evidence is not evidence of absence. A site with no visible provider might run three of them behind a router, or none.

Bassethound treats this honestly. A purely server-side or fully proxied component stays invisible to a static crawl plus optional rendering, and the dossier says so in its gaps instead of filling the hole with a guess. A tool that always names a provider is not seeing more than Bassethound. It is inferring, usually from a job post or a press release, and calling the inference a detection.

Do AI chat widgets tell you the provider?

Only that AI is present, not which model runs it. Widgets like Intercom Fin and Sierra load recognizable third-party script, so they are easy to fingerprint and they are a genuine AI-readiness signal: the company shipped a customer-facing AI feature and paid for it. That is worth knowing. It is not provider attribution.

These products abstract the model on purpose. A Fin deployment tells you the company bought an AI support layer, not that they run OpenAI or Anthropic directly, and the vendor can swap or blend models underneath without the customer touching anything. So folding a widget into a provider claim manufactures precision that is not there. Keep the two questions apart. Question one, does this company ship AI, is answered by the widget. Question two, which provider, is answered only by provider SDK code or a direct call, which the widget does not expose. Bassethound records the widget under AI signals and leaves the provider field empty unless a separate signal fills it, so the dossier never launders “has a chatbot” into “uses GPT.”

Does the Vercel AI SDK give the provider away?

Often, yes, and this is one of the cleaner tells. The Vercel AI SDK splits providers into separate packages rather than one monolith. When a client bundle pulls in provider-specific code, the provider name rides along as an import path or identifier and survives minification, because the string is load-bearing, not cosmetic. See a provider package in the shipped bundle and you have a strong lead on which model the app targets.

The catch is where the call runs. If the app invokes the model from a server route or an edge function, the provider package stays server-side and the browser never receives it. Then the SDK is silent and you are back to proxied invisibility. So the Vercel AI SDK is a strong signal when it ships to the browser and no signal at all when it does not. Same library, opposite visibility, depending on one architectural choice.

Bassethound fingerprints the AI SDKs it can reach (the Anthropic SDK, the OpenAI SDK, the Vercel AI SDK) and uses a provider-specific package as a provider hit, not just a generic “uses AI” flag. When the package is server-only, that shows up as a gap, consistent with how the rest of the dossier handles what it cannot see.

How does Bassethound report the answer, and how sure is it?

Bassethound fingerprints model providers in the AI-readiness layer of a five-layer dossier, from a static crawl plus optional JS rendering, keyless and read-only. It reports the providers it can see (Anthropic, OpenAI, Gemini, Cohere, Mistral), the SDKs it matched, and it rolls those into an ai_readiness score, the count of distinct signal groups hit out of six, capped at 1.0. The verdict summarizes intent: shipping when a machine-facing endpoint is present or at least three signal groups fire, experimenting when at least one fires, none when the trail is empty.

Confidence is explicit, not implied. One matched signal is a lead. Two that agree is a confident match. A proxied or server-side provider is a gap, stated plainly, so you can tell “we looked and it is hidden” from “there is nothing here.” Bassethound also emits an icp_signal (hot, warm, cold) so a shipping stack with a visible provider ranks above a bare landing page. One domain in, one correlated dossier out, no key required.

Bassethound perspective

Provider attribution is where most AI-readiness tools quietly lie. Data-enrichment vendors will hand you a confident “this company uses OpenAI” label, and most of the time that label came from a job posting, a conference talk, or a press quote, not from the running application. We think that is unverifiable dressed up as a fact, and we will say so. Here is the conviction a competitor would dispute: for any app built past prototype stage, the provider call is proxied server-side, which means the correct answer from the outside is frequently “cannot see it,” and a tool that names a provider anyway is guessing. We would rather return a gap than a fabricated match, because a wrong provider label is worse than an honest blank. It sends your outbound to the wrong pitch and burns the lead. So Bassethound reports exactly what the code path reveals: the providers whose SDKs or model strings ship, and a clearly marked blind spot everywhere the call is hidden. That is less flattering than a full-color enrichment record. It is also true, which is the only version worth selling on.

Sources

Frequently asked questions

Can you detect the provider if the API call happens on the server?

No. When the app proxies the model through its own backend, api.anthropic.com and api.openai.com never touch the browser, so there is nothing to fingerprint. Bassethound reports this as a gap in the dossier rather than guessing a provider.

Does a model ID string like claude-... or gpt-... confirm the provider?

It is a strong lead, especially paired with a matching SDK. On its own a bare string can be a stale reference or a comment, so Bassethound treats one signal as a lead and two aligned signals as a confident match.

Do you need JavaScript rendering to find the provider?

Partly. Server-rendered SDK imports and model strings show up in static HTML. A client that only initializes in the browser needs JS rendering. Bassethound renders when the signals call for it and notes what it could not reach.

Can a company use both Anthropic and OpenAI?

Yes. Many route across providers for cost, fallback, or per-feature fit. Bassethound reports every provider it can see, not a single winner, so a multi-provider stack shows up as multiple hits in the AI-readiness layer.

Does an Intercom Fin or Sierra widget tell you the provider?

No. Those widgets confirm the company ships an AI feature, but they abstract the underlying model. Treat a widget as an AI-readiness signal, not as provider attribution, and keep the two questions separate.

Sniff a domain.

Run sniff_domain on any site and read its five-layer dossier in one call.

Sniff a domain