Skip to content

Handle files

Published

In one line: declaring file_handlers in your Web App Manifest registers your installed PWA with the OS as a handler for specific file types, so double-clicking or “Open with”-ing a matching file launches your app with that file instead of you building a separate import flow.

Per Chrome for Developers, each file handler needs an action URL within the app’s scope, an accept map of MIME types to file extensions, and an optional icons array so the OS can show a file-type-specific icon instead of just the app icon:

{
"file_handlers": [
{
"action": "/open-csv",
"accept": { "text/csv": [".csv"] },
"icons": [
{ "src": "/icons/csv-icon.png", "sizes": "256x256", "type": "image/png" }
],
"launch_type": "single-client"
}
]
}

launch_type controls whether opening multiple matching files at once reuses a single app window ("single-client", the default) or, with "multiple-clients", launches the app once per file, each launch’s LaunchParams.files array holding just that one file.

2. Consume the launched file with launchQueue

Section titled “2. Consume the launched file with launchQueue”

Per MDN, once the OS launches the app with a matching file, the app receives it through window.launchQueue.setConsumer():

window.launchQueue.setConsumer(async (launchParams) => {
if (!launchParams.files.length) {
return;
}
const [fileHandle] = launchParams.files;
const file = await fileHandle.getFile();
const text = await file.text();
renderCsv(text);
});
  • Legend
  • Yes
  • Partial
  • Flag
  • No
  • Unknown
Browser / PlatformSupportVersionsConfidenceSourceNotes
Chrome (Desktop)Yes102highsource—
Chrome (Android)No—highsource1
Edge (Desktop)Yes102highsource2
Firefox (Desktop)No—highsource3
Firefox (Android)No—highsource45
Safari (macOS)No—highsource6
Safari (iOS)No—highsource78
Samsung InternetNo—highsource910
WebView (Android)No—highsource1112
  1. No Chrome Android support is recorded in browser-compat-data.
  2. Derived by browser-compat-data mirroring from Chrome.
  3. No Firefox support is recorded in browser-compat-data.
  4. No Firefox for Android support is recorded in browser-compat-data.
  5. Derived by browser-compat-data mirroring from Firefox.
  6. No Safari support is recorded in browser-compat-data.
  7. No Safari on iOS support is recorded in browser-compat-data.
  8. Derived by browser-compat-data mirroring from Safari.
  9. No Samsung Internet support is recorded in browser-compat-data.
  10. Derived by browser-compat-data mirroring from Chrome Android.
  11. No WebView Android support is recorded in browser-compat-data.
  12. Derived by browser-compat-data mirroring from Chrome Android.

Source data: /compatibility/manifest-file-handlers.json · Global usage: 37 % (StatCounter 2026-05)

Source: spec · MDN · Last verified 2026-10-03 · Confidence: high (computed from sources)

Per Chrome for Developers, File Handling is “limited to desktop operating systems” in Chromium’s implementation — do not rely on it to associate files with the app on Android.

Per Chrome for Developers, feature-detect with both "launchQueue" in window and "files" in LaunchParams.prototype, since launchQueue alone does not confirm the files parameter shape the consumer depends on. When either check fails, give users an in-app way to open a file that doesn’t depend on OS registration:

function supportsFileHandling() {
return 'launchQueue' in window && 'files' in LaunchParams.prototype;
}
if (supportsFileHandling()) {
window.launchQueue.setConsumer(async (launchParams) => {
if (!launchParams.files.length) return;
const file = await launchParams.files[0].getFile();
renderCsv(await file.text());
});
} else {
// No File Handling support here — fall back to a manual
// <input type="file" accept=".csv"> picker in the UI.
document.getElementById('open-file-input').hidden = false;
}
  • file_handlers registration is desktop-only in Chromium, per Chrome for Developers — always ship an in-app file picker as the Android/fallback path.
  • Feature-detect with both "launchQueue" in window and "files" in LaunchParams.prototype, per Chrome for Developers — checking launchQueue alone doesn’t confirm the files parameter shape setConsumer() callbacks depend on.
  • Per Chrome for Developers, launchQueue queues launches until a consumer is registered, and each launch is handled exactly once regardless of when the consumer is set — but the consumer function itself must still run before you can read the launched file, so don’t gate its registration behind other async startup work.
  • Firefox and Safari do not implement file_handlers — do not depend on OS-level file association as the only way into this feature.