Something went wrong while trying to load more search results.
We apologize for the inconvenience caused.
Please try again later.


Something went wrong…

…while trying to load the search results.
We apologize for the inconvenience caused.
Please try again later.


Allows running custom JavaScript to render UI.

Required Script
<script async custom-element="amp-script" src=""></script>


The amp-script component allows you run custom JavaScript to render UI elements, such as a React component.

A simple example

An amp-script element can load a JavaScript file from a URL:

<!-- Use an remote script via the "src" attribute. -->
<amp-script layout="container" src="">
  <button>Hello amp-script!</button>

...or reference a local script element by id:

<!-- Local scripts require adding a "script hash" to the document head. -->
  <!-- ... -->

<!-- Reference a local script by [id] via the "script" attribute. -->
<amp-script width=200 height=50 script="hello-world">
  <button>Hello amp-script!</button>

<!-- Local scripts must also have [target="amp-script"]. -->
<script id="hello-world" type="text/plain" target="amp-script">
  const btn = document.querySelector('button');
  btn.addEventListener('click', () => {
    document.body.textContent = 'Hello World!';

amp-script elements that use local scripts or cross-origin src require adding a <meta name="amp-script-src" content="sha384-HASH"> to the document head, where HASH is a base64-encoded SHA-384 of the script source (similar to CSP's script-src).

A console error will be generated with the expected HASH value for affected amp-script elements. You can copy/paste from the error to create the appropriate <meta> tag.

How does it work?

amp-script runs your custom JavaScript in a Web Worker that contains a virtual DOM. When your JavaScript code modifies this virtual DOM, amp-script forwards these changes to the main thread and applies them to the amp-script element subtree.

For example, adding an element to document.body:

// my-script.js
const p = document.createElement('p');
p.textContent = 'I am added to the body!';

Will be reflected on the page as a new child of the amp-script element:

<amp-script src="" width=300 height=100>
  <p>I am added to the body!</p>

Under the hood, amp-script uses @ampproject/worker-dom. For design details, see the "Intent to Implement" issue.


Size of JavaScript code

amp-script has the following restrictions on JavaScript file size:

  • Maximum of 10,000 bytes per amp-script element that uses a local script via script[type=text/plain][target=amp-script].
  • Maximum total of 150,000 bytes for all amp-script elements on the page.

User gestures

amp-script generally requires a user gesture to apply changes triggered by your JavaScript code to the page (we call these "mutations"). This requirement helps avoid poor user experience from unexpected content jumping.

The rules for mutations are as follows:

  1. Mutations are always accepted for five seconds after a user gesture.
  2. The five second interval is extended if the author script performs a fetch() as a result of the user gesture.
  3. Mutations are always accepted for amp-script elements with [layout!="container"] and height < 300px.

Security features

Since custom JS run in amp-script is not subject to normal Content Security Policy, we've included some additional measures that are checked at runtime:

  • Same-origin src must have Content-Type: application/json.
  • Cross-origin src and local scripts must have matching script hashes in a meta[name=amp-script-src] element in the document head. A console error will be emitted with the expected hash string. For example:
  <!-- Script hashes are space-delimited. -->
    content="sha384-abc123 sha384-def456">
  <!-- Cross-origin [src] requires hash: sha384(example.js) == "abc123" -->
  <amp-script src="cross.origin/example.js" layout=container>

  <!-- Local script requires hash: sha384(#myScript) == "def456" -->
  <amp-script script=myScript layout=container>
  <script type=text/plain target=amp-script id=myScript>
    document.body.textContent += 'Hello world!';

The JavaScript size and script hash requirements can be disabled during development by adding a development attribute to an amp-script element.



The URL of a JS file that will be executed in the context of this <amp-script>.


The id of a script[type=text/plain][target=amp-script] element whose text content contains JS that will be executed in the context of this <amp-script>.

sandbox (optional)

Applies extra restrictions to DOM that may be mutated by this <amp-script>. Similar to the iframe[sandbox] attribute, the value of the attribute can either be empty to apply all restrictions, or space-separated tokens to lift particular restrictions:

  • allow-forms: Allows form elements to be created and modified. AMP requires special handling to prevent unauthorized state changing requests from user input. See amp-form's security considerations for more detail.

common attributes

This element includes common attributes extended to AMP components.

Interested in using amp-script?

We recommend developing against a local build of amp-script. This enables dev-only debugging hooks e.g. human-readable postMessage events.

See our Quick Start guide for setting up your local environment.


Which JavaScript APIs can I use?

Currently, most DOM elements and their properties are supported. DOM query APIs like querySelector have partial support. Browser APIs like History are not implemented yet.

See the API compatibility table for details.

Can you support ____ API?

Our feature timelines are informed by your real-world use cases! Please file an issue and mention @choumx and @kristoferbaxter.

I'm getting a "maximum total script size exceeded" runtime error.

amp-script limits the size of the JS source that may be used. See Size of JavaScript code above.

I'm getting a "script hash not found" runtime error.

Local scripts and cross-origin src require adding a special <meta> tag to be used. See Security features above.

I'm getting a "custom JavaScript is not allowed" validation error.

Currently, local scripts are not valid AMP. We're working on fixing this soon (issue #24171).

I'm getting a "amp-script... was terminated due to illegal mutation" runtime error.

To avoid unexpected content jumping, amp-script generally requires user gestures for DOM changes. See User gestures above.


You've read this document a dozen times but it doesn't really cover all of your questions? Maybe other people felt the same: reach out to them on Stack Overflow.

Go to Stack Overflow
Found a bug or missing a feature?

The AMP project strongly encourages your participation and contributions! We hope you'll become an ongoing participant in our open source community but we also welcome one-off contributions for the issues you're particularly passionate about.

Go to GitHub