Unlock Structured Clone for Chrome Extension Messaging

Justin Lulejian
Justin Lulejian

Published: April 13, 2026

The communication between different extension components (background scripts, content scripts, popups) has traditionally relied on JSON serialization. While reliable, JSON has limitations.

We are excited to announce that starting in Chrome 148, extension developers can opt-in to use the structured clone algorithm for message serialization instead of JSON! This modernization lets you send more complex data types between your extension contexts without manual serialization workarounds.

Why structured clone?

JSON serialization (via JSON.stringify under the hood) is functional, but it sometimes requires developers to jump through hoops when dealing with modern JavaScript types.

Here's a specific example you might've run into when developing an extension:

// Sending a Map with JSON serialization
const myMap = new Map([['id', 123]]);

// Arrives as {} on the other side!
chrome.runtime.sendMessage(myMap);

// Workaround: Convert Map to an Array of entries before sending
const message = Array.from(myMap.entries());
chrome.runtime.sendMessage(message);

// On the receiving side:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  const receivedMap = new Map(message);
});

Some other situations where JSON fails that you might've had to workaround are Set, BigInt, NaN and Infinity, Date, and Error Objects.

Using structured clone serialization means you can now send various objects that were previously difficult or impossible to transmit over extension messaging. For example, sending a Map object is now direct:

// Sending a Map with Structured Clone
const myMap = new Map([['id', 123]]);

// Arrives as a Map on the other side!
chrome.runtime.sendMessage(myMap);

// On the receiving side:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  // message is already a Map instance!
  console.log(message.get('id')); // 123
});

More supported types

Structured clone supports a wide array of other types such as File and Blob.

How to opt-in

To ensure backwards compatibility and prevent breaking existing extensions, this feature is opt-in. You can enable it globally for your extension by adding a single key to your manifest.json:

{
  "name": "My Extension",
  "version": "1.0",
  "manifest_version": 3,
  "message_serialization": "structured_clone"
}

If omitted, or on a Chrome version lower than 148, the browser defaults to its current JSON-based implementation for the extension.

By supporting the structured clone algorithm, we are bringing the extension messaging API closer to alignment with standard web platform capabilities (similar to postMessage used in Web Workers and iframe communication), giving you more flexibility and power.

Interoperability and gotchas

While our structured clone serialization implementation supports many more types than JSON, there are a few architectural assumptions and incompatibilities with the implementation you should keep in mind.

Unsupported types

Shared objects like SharedArrayBuffer and transferring of objects like ArrayBuffer are not supported with our implementation. SharedArrayBuffer will fail to serialize or deserialize (depending on the situation), and attempting to send a transferable object like Uint8Array will send a copy instead.

Extension to extension communication

We enforce matching serialization formats to ensure data integrity. Extensions with mismatched serialization formats cannot communicate directly over runtime.sendMessage or runtime.connect. For example, if extension A uses JSON serialization and tries to message Extension B using structured clone, the message will fail to send and the port will close (and vice versa).

Web page communication

Web Pages using externally_connectable will automatically adapt to the target extension's serialization format. If your extension uses structured clone, web contexts sending messages using the runtime API will use structured clone (and vice versa) automatically. This means the web site and extension must be in sync on their expected serialization format to prevent serialization errors.

Native messaging

Native messaging channels continue to always force JSON serialization. Attempting to send structured-clone-only types (like a BigInt) to a native host will fail before a message leaves your extension's context.

toJSON() methods

If you use classes or objects with custom toJSON() methods to perform custom serialization (for example, sanitizing data by removing passwords before sending an object), be aware that structured clone ignores toJSON(). It copies property values directly. If you rely on toJSON() for custom serialization, some manual work might be required before sending. For example:

class User {
  constructor(name, password) {
    this.name = name;
    this.password = password;
  }

  // This will be ignored by structured clone!
  toJSON() {
    return { name: this.name };
  }
}

const user = new User("Alice", "secret123");

// JSON -> {"name":"Alice"}
// Structured Clone -> { name: "Alice", password: "secret123" }

Is JSON serialization going away?

No! Chrome is committed to supporting both serialization formats for the foreseeable future.

Share feedback

We hope this new capability unlocks smoother and more powerful workflows for your extension development.

While we have created a test suite to validate functionality for our structured clone implementation, the web platform has a massive variety of objects. Try out this new feature and report any bugs or edge cases you encounter! Your feedback will help us improve the implementation for the entire community.