Do you build things with AMP? Fill out the new AMP Developer Survey!



Allows running custom JavaScript to render UI.

Required Scripts

<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 JavaScript in two ways:

  • Remotely, from a URL to a JavaScript file.
  • Locally, from a script[type=text/plain][target=amp-script] element on the page.

Load JavaScript from a remote URL

Use the src attribute to load remote JavaScript.

<amp-script layout="container" src="">
  <button>Hello amp-script!</button>

If src points to a cross-origin URL, then a "script hash" must also be added to the document head.

Load JavaScript from a local element

Use the script attribute to reference a local script element by id.

<!-- Using the "script" attribute also requires adding a "script hash" to the document head. -->


<amp-script width="200" height="50" script="hello-world">
  <button>Hello amp-script!</button>

<!-- Also add [target="amp-script"] to the <script> element. -->
<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 have a script or cross-origin src attribute require a "script hash". Script hashes are specified in a <meta name="amp-script-src" content="..."> element in the document head.

A console error will be thrown with the expected content value -- 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.

State manipulation

amp-script supports getting and setting amp-state JSON via JavaScript.

This enables advanced interactions between amp-script and other AMP elements on the page via amp-bind bindings. Invoking AMP.setState() from amp-script may cause mutations to the DOM as long as it was triggered by user gesture, otherwise it will only implicitly set state (similar to amp-state initialization).

AMP.setState() requires the amp-bind extension script to be included in the document head.

 * Deep-merges `json` into the current amp-state.
 * @param {!Object} json A JSON object e.g. must not contain circular references.
AMP.setState(json) {}

 * Asynchronously returns amp-state.
 * @param {string=} expr An optional JSON expression string e.g. "".
 * @return {!Promise<!Object>}
AMP.getState(expr) {}
Example with WebSocket and AMP.setState()
<amp-script width="1" height="1" script="webSocketDemo"> </amp-script>

  <amp-state> doesn't support WebSocket URLs in its "src" attribute,
  but we can use <amp-script> to work around it. :)
<script type="text/plain" target="amp-script" id="webSocketDemo">
  const socket = new WebSocket('wss://websocket.example');
  socket.onmessage = event => {


Allowed APIs

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.

If there's an API you'd like to see supported, please file an issue and mention @choumx and @kristoferbaxter.

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

In some cases, amp-script requires a user gesture to apply changes triggered by your JavaScript code (we call these "mutations") to the amp-script's DOM children. This helps avoid poor user experience from unexpected content jumping.

The rules for mutations are as follows:

  1. For amp-script elements with non-container layout, mutations are always allowed.
  2. For amp-script elements with container layout, mutations are allowed for five seconds following a user gesture. This five second window is extended once if a fetch() is triggered.

Creating AMP elements

With regard to dynamic creation of AMP elements (e.g. via document.createElement()), only amp-img and amp-layout are currently allowed. Please upvote or comment on #25344 with your use case.

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:

  1. Same-origin src must have Content-Type: application/javascript or text/javascript.
  2. Cross-origin src and script 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.

Example of script hashes:

    A meta[name="amp-script-src"] element contains all script hashes for
    <amp-script> elements on the page, delimited by spaces.
    A "src" attribute with a cross-origin URL requires adding a script hash.

    If the hash of remote.js's contents is "fake_hash_of_remote_js",
    we'll add "sha384-fake_hash_of_remote_js" to the <meta> tag above.
  <amp-script src="cross.origin/remote.js" layout=container>

    A "script" attribute also requires adding a script hash.

    If the hash of #myScript's text contents is "fake_hash_of_local_script",
    we'll add "sha384-fake_hash_of_local_script" to the <meta> tag above.
  <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 data-ampdevmode attribute to either the amp-script element or the root html node.



For executing remote scripts.

The URL of a JS file that will be executed in the context of this <amp-script>. The URL's protocol must be HTTPS and the HTTP response's Content-Type must be application/javascript or text/javascript.


For executing local scripts.

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.

max-age (optional, but required for signed exchanges if script is specified)

Requires the script attribute.

The max-age attribute specifies the maximum lifetime in seconds the local script is allowed to be served from the time of signed exchange (SXG) publishing. AMP Packager uses this value to compute the SXG expires time.

The value of max-age should be chosen carefully:

  • A longer max-age increases the potential security impact of a SXG downgrade.

  • A shorter max-age may prevent inclusion in AMP Caches that have a minimum SXG lifetime. For instance, the Google AMP Cache requires at least 4 days (345600 seconds). Note that there's currently no reason to select max-age longer than 7 days (604800 seconds), due to the maximum set by the SXG spec.

If you don't publish signed exchanges, max-age does nothing.

common attributes

This element includes common attributes extended to AMP components.


There are several types of runtime errors that may be encountered when using amp-script.

"Maximum total script size exceeded (...)"

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

"Script hash not found."

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

"amp-script... was terminated due to illegal mutation"

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

Ti servono altre informazioni?

Hai letto questo documento decine di volte ma non risponde a tutte le tue domande? Forse ci sono altre persone col tuo stesso problema: entra in contatto con loro su Stack Overflow.

Vai a Stack Overflow
Hai trovato un bug o una funzione mancante?

Il progetto AMP invita tutti a partecipare e dare il proprio contributo! Ci auguriamo che tu possa partecipare regolarmente alla nostra community open source, ma saremo anche lieti di ricevere eventuali contributi una-tantum sulle questioni che ti interessano.

Vai a GitHub