How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: Fix “URL.createObjectURL is not a function” in Chrome Extension Service Workers
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > Web Development > Fix “URL.createObjectURL is not a function” in Chrome Extension Service Workers
Web Development

Fix “URL.createObjectURL is not a function” in Chrome Extension Service Workers

how7o
By how7o
Last updated: May 23, 2026
5 Min Read
URL.createObjectURL not a function — Chrome extension service worker fix
SHARE

If you see TypeError: URL.createObjectURL is not a function in a Chrome extension service worker, the cause is straightforward: that API isn’t available in service-worker contexts. Manifest V3 replaced the background page (which had a DOM) with a service worker (which doesn’t), and URL.createObjectURL requires a document. Switch to FileReader.readAsDataURL to make a data: URL instead, which works without a DOM.

Contents
  • The broken version
  • The fix — use a data URL
  • Alternative — let Chrome download the URL directly
  • If you really need a blob URL — do it from a content script
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-05-17 with Chrome 124 (Manifest V3). Originally published 2022-09-16, rewritten and updated 2026-05-17.

The broken version

// In background.js (MV3 service worker)
fetch(url).then(data => {
    let dataUrl = URL.createObjectURL(data.blob());   // TypeError
    chrome.downloads.download({ url: dataUrl, filename: 'image.png' });
});

Two bugs: data.blob() returns a promise that has to be awaited, and URL.createObjectURL isn’t available in service workers.

MV3 service worker — no URL.createObjectURL, use FileReader.readAsDataURL for data: URL, content script for blob URL

The fix — use a data URL

async function downloadImage(url, filename) {
    const res  = await fetch(url);
    const blob = await res.blob();

    const reader = new FileReader();
    reader.readAsDataURL(blob);
    reader.onloadend = () => {
        chrome.downloads.download({
            url:      reader.result,    // "data:image/png;base64,..."
            filename: filename || 'image.png',
        });
    };
}

FileReader.readAsDataURL produces a complete data: URL — a base64-encoded inline representation of the blob. The result works wherever a URL string works, including the url parameter of chrome.downloads.download. No DOM required.

Alternative — let Chrome download the URL directly

// If you don't need to inspect or modify the bytes, just pass the URL straight through
chrome.downloads.download({
    url:      'https://example.com/image.png',
    filename: 'image.png',
});

The downloads API does its own fetching — for a public URL, skipping the fetch+blob round-trip avoids the problem entirely.

If you really need a blob URL — do it from a content script

// content.js — runs in the page context, has a DOM
const res  = await fetch(url);
const blob = await res.blob();
const blobUrl = URL.createObjectURL(blob);

// Then pass it back to the service worker if it needs to act on it
chrome.runtime.sendMessage({ action: 'download', url: blobUrl });

Blob URLs are scoped to the document that created them — so the content script must be the one that calls chrome.downloads.download, or wire the actual download up through a message-passed proxy.

Frequently asked questions

Why isn’t URL.createObjectURL available in MV3 service workers?

Manifest V3 replaced the background page with a service worker, which doesn’t have a DOM. URL.createObjectURL requires a document context to produce blob URLs scoped to a window — service workers have no window, so the function is undefined. Use a data: URL (from FileReader.readAsDataURL) or do the work from a content script / popup that does have a document.

What’s the difference between a blob URL and a data URL?

A blob URL (blob:...) is a pointer to in-memory data, scoped to the document that created it; the actual bytes never leave the browser. A data URL (data:image/png;base64,...) embeds the bytes inline as base64-encoded text. Data URLs are bigger (~33% overhead) but self-contained — they work anywhere a URL works, including in MV3 service workers.

Will this work for large files?

Yes, but a data URL inflates the size by ~33%. For multi-MB files, the encoded string can get large enough to stress memory in a service worker. If you’re downloading something huge, consider doing the download from a content script (which has a document and can use URL.createObjectURL) or pass the blob to chrome.downloads.download via a more recent API. For most images, the data-URL approach is fine.

Where should I do this — background script or content script?

MV3 service worker for headless background work (cron-like scheduled tasks, network calls). Content script for anything that needs DOM access (parsing pages, blob URLs). Popup for UI-driven actions. Move the function that creates the URL into a context where the right APIs exist.

Related guides

  • How to Convert an Image to a Base64 String in JavaScript
  • How to Get a Website’s Favicon URL with JavaScript
  • How to Remove the “Other Favorites” Button in Microsoft Edge

References

Chrome extensions: Migrating to Manifest V3: developer.chrome.com/docs/extensions/develop/migrate. chrome.downloads: developer.chrome.com/docs/extensions/reference/api/downloads. MDN FileReader.readAsDataURL: developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL.

TAGGED:browser-extensionchromeJavaScript

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Fix CSS page breaks not working with HTML tables Why CSS Page Breaks Don’t Work in HTML Tables (and How to Fix It)
Next Article yum/dnf -y flag explained What Does the -y Flag Do in yum / dnf / apt-get?
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow
Most Popular
Set vi as the default editor in Ubuntu — a terminal opening the vim editor
How to Set vi (Vim) as the Default Editor in Ubuntu
June 8, 2026
rsync says ALL DONE but files are missing — a terminal showing ALL DONE next to an empty folder
rsync Says “ALL DONE” but Files Are Missing: How to Verify
June 8, 2026
Migrate a website to a new server with rsync — files copying from an old server to a new one over SSH
How to Migrate a Website to a New Server With rsync
June 8, 2026
Bun runtime — faster JS toolkit replacing npm in Laravel projects
How to Install Bun Runtime on Ubuntu (And Use It in a Laravel Project)
May 24, 2026
Tailscale mesh — peer-to-peer connections between devices, coordination server
How to Install Tailscale on Ubuntu (Zero-Config Mesh VPN for Self-Hosters)
May 24, 2026

You Might Also Like

WordPress logged-in menu swap — register_nav_menus + wp_nav_menu with is_user_logged_in ternary
Web Development

How to Display Different Menus to Logged-In Users in WordPress

7 Min Read
Validate an email address in PHP with filter_var
Web Development

How to Validate an Email Address in PHP

5 Min Read
Laravel migration adding two new columns to an existing transactions table
Web Development

How to Add New Columns to an Existing Table in Laravel Migration

5 Min Read
Keep the first N characters of a JavaScript string with slice
Web Development

How to Keep Only the First N Characters of a String in JavaScript

4 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?