Browser AI · Tech

An unavailable status is a starting clue, not a diagnosis

Read the policy result and the requested options alongside the status before choosing a fix.

  1. API presence is a weak signalBoth test pages exposed LanguageModel, yet both returned unavailable.
  2. Policy needs its own checkOne page allowed language-model and the other denied it; the availability strings matched.
  3. Match the intended sessionCheck the exact input and output options before any user-triggered create() call.

Chrome's Prompt API can expose LanguageModel and still return unavailable. That result is useful, but it is not a diagnosis. The page might be blocked by the language-model permissions policy, the browser or device might not meet a prerequisite, or the requested input and output options might not be supported. The first productive question is therefore not “How do I force the model to download?” It is “Which condition have I actually measured?”

One status can describe different situations

Chrome documents four availability states: available, downloadable, downloading and unavailable. The first three guide a product's user experience; unavailable says the proposed session cannot currently be used. The status does not contain a reason code. MDN separately documents that a policy denying language-model can return unavailable. A page that only checks whether LanguageModel exists and then reads the status has skipped a gate that may determine the answer.

We tested this distinction with two pages served by the same temporary local HTTP server. Both were secure contexts because they used localhost; both ran in the same headless Chrome 153.0.8010.50 installation. One route had no restrictive Permissions-Policy header. The other returned Permissions-Policy: language-model=(). We asked for the default availability and for an English text-in/text-out session. We did not call LanguageModel.create(), request a model download or send a prompt.

Two pages with opposite language-model policy states both returned unavailable from LanguageModel.availability() in a local Chrome 153 test
Tap the diagram to read it at full size. The policy-denied route supplies one known explanation. The test did not determine why the policy-allowed route was also unavailable; no model was created or downloaded.

Policy allowed

allowsFeature('language-model') → true

LanguageModel.availability() → unavailable

Policy denied

allowsFeature('language-model') → false

LanguageModel.availability() → unavailable

Both routes exposed the LanguageModel global. In the unrestricted route, document.featurePolicy.allowsFeature('language-model') was true; in the restricted route it was false. Both LanguageModel.availability() calls returned unavailable, with or without the explicit English text options. That is the point of the comparison: the same visible status coexisted with opposite policy states. The unrestricted route's result does not tell us whether the device, model installation, browser configuration or another prerequisite caused its unavailable status. We did not isolate those variables.

Run a read-only diagnosis before creating a session

Start in the exact page or frame where the feature will run. Check isSecureContext and whether LanguageModel is present there. The current Prompt API is a Window API; a worker result is not interchangeable with a top-level page result. If the API is absent, stop interpreting model status and check browser support and execution context first. Do not infer that a missing global proves a GPU or storage failure.

Next, inspect the active permissions policy. In Chrome, document.featurePolicy?.allowsFeature('language-model') gives a useful browser-side check; where supported, the newer document.permissionsPolicy interface can be used. A false value identifies a policy block. A true value means this policy check passed, not that the model is ready. In a cross-origin iframe, the embedding page may need an allow="language-model" attribute; a top-level page can also restrict itself with an HTTP header. If the policy object or method is absent, record unknown rather than silently equating it with permission.

const opts = {
  expectedInputs: [{ type: 'text', languages: ['en'] }],
  expectedOutputs: [{ type: 'text', languages: ['en'] }]
};
const policy = document.permissionsPolicy ?? document.featurePolicy;
const policyAllows = policy?.allowsFeature?.('language-model') ?? null;
const result = { secureContext: isSecureContext,
  apiPresent: typeof LanguageModel !== 'undefined', policyAllows };
if (result.apiPresent) {
  try { result.availability = await LanguageModel.availability(opts); }
  catch (error) { result.error = error.name; }
}
console.table(result);

The final read-only call must describe the feature you actually plan to offer. Chrome specifically warns to pass the same options to availability() that you will use for the intended prompt. If the product expects English text input and text output, use those options for the check. A default check followed by an image, audio or different-language session answers a different question. Keep the same options through the later session path, and handle rejected calls separately from returned states.

Interpret each observation without guessing a cause

When policy is denied, fix the header or frame delegation before looking for a model installation. When policy is allowed but the status is still unavailable, the policy check has eliminated only one explanation. Chrome's current developer documentation lists supported desktop platforms, at least 22 GB free space on the Chrome-profile volume, and either a GPU with more than 4 GB VRAM or a CPU path with at least 16 GB RAM and four cores. The initial model download also needs an unmetered connection. These are prerequisites to check against the current documentation, not a claim that our test machine failed one of them. Managed-browser policy and requested modality or language may add further constraints.

If the result is downloadable or downloading, the interface should explain the model download rather than treating it as instantaneous. Chrome says the model is separate from the API, and recommends user activation before create() triggers installation. The download state is a UX event, not a reason to call create() during a passive diagnostic. Only after a deliberate user action should the product attempt session creation, monitor progress and handle its errors. This article's experiment deliberately stopped before that stage.

The distinction is similar to a performance trace: seeing a browser capability is weaker evidence than seeing it complete the intended work. Our earlier look at Windows Task Manager's AI workload signals separates a visible accelerator counter from a successful model result. A Chrome notification permission similarly says less about continuing delivery than a live end-to-end test. Here, LanguageModel being present says less than a permitted, supported, created session.

What our local comparison proves and leaves open

The test establishes a narrow, practical fact in Chrome 153: unavailable did not distinguish an explicitly denied language-model policy from a page on which that policy check passed. It also shows why recording the policy result alongside availability improves a bug report. The result is not a survey of Chrome installations, a hardware eligibility test, a model-output quality test or proof that every browser implements the draft API identically. A newer browser may change behavior; rerun the probe against the version you support.

For a reproducible report, record the browser version, page/frame context, secure-context result, effective policy result, exact availability() options, status or exception, and whether a session was actually created. If create() is never called, say so. If it is called later, report its error independently. That small record gives another engineer a testable claim instead of a screenshot of one ambiguous word.

Questions developers ask

Does LanguageModel being present prove the model is installed?

No. The API can be exposed while availability is unavailable. Model readiness and session creation are separate observations.

Can I create a session just to diagnose an unavailable status?

Avoid doing so in a passive check. Chrome documents that create() can trigger a model download. First collect read-only context, policy and matched availability results; create a session after a deliberate user action.

Why is my iframe different from the top-level page?

The language-model permissions policy can be delegated or restricted per frame. Measure the effective policy in the same frame where the API will run.

Documentation and experiment scope

Documentation and experiment provenance

Local experiment: Chrome 153.0.8010.50, two localhost routes with and without Permissions-Policy: language-model=(), default and English text availability calls. Test record and runner are retained in the manual run and workspace. No model session or prompt was created.