Gatsby Script API
Examples
Support for the Gatsby Script API was added in
gatsby@4.15.0
.
Gatsby includes a built-in <Script>
component that aids in loading scripts performantly.
It offers a convenient way to declare different loading strategies, and a default loading strategy that gives Gatsby users strong performance out of the box. It supports both scripts with sources and inline scripts.
Whether you want to leave the heavy lifting of managing scripts to Gatsby or you want maxiumum flexibility and control, the Gatsby <Script>
component is a great tool for the job.
Using Gatsby Script in your site
Here is an example of how you can import and use the <Script>
component in your site’s JSX or TSX source files:
If you have existing scripts, using the Gatsby <Script>
component is as simple as importing Script
and changing lowercase script
tag names to capitalized Script
tag names in most cases:
By default, the <Script>
component will load your script after hydration. For more information on declaring loading strategies, see the Strategies section.
Scripts with sources and inline scripts
There are two types of scripts that you can tell the <Script>
component to load:
- Scripts with sources
- Inline scripts
Scripts with sources
Scripts with sources provide a src
property like this:
The <Script>
component will use the value of src
to deduplicate loading, so if you include two scripts on the same page with the same src
, only one will load.
If for some reason you need to load two scripts with the same sources on the same page, you can provide an optional, unique id
property to each and the <Script>
component will attempt to load both:
Inline scripts
Inline scripts must include a unique id
property and can be defined in two ways:
- Via React’s special
dangerouslySetInnerHTML
property - Via a template literal
Here’s a look at both:
Functionally, both of these ways of defining inline scripts are equivalent.
Strategies
You can declare a loading strategy by passing a strategy
property. These are the available loading strategies:
post-hydrate
(default) - Loads after the page has hydratedidle
- Loads after the page has become idleoff-main-thread
(experimental) - Loads off the main thread in a web worker via Partytown
Here’s how you can define these strategies in the <Script>
component:
Additionally, Gatsby exports a ScriptStrategy
enum that you can use in TSX files if you prefer:
Post hydrate strategy (default)
The post-hydrate
strategy is the default loading strategy and will be used if you do not specificy a strategy
attribute.
The advantage of this strategy is that you have the ability to declare that your script should start loading after hydration. This is impactful because hydration is what makes your page interactive, and by using regular <script>
tags (even with async
or defer
applied), you run the risk of your script being loaded in parallel with the framework JavaScript that hydrates your page.
This can have negative implications for key web vital metrics like Total Blocking Time. By leveraging the <Script>
component with the post-hydrate
strategy, you ensure that your script avoids interfering with your page reaching an interactive state, resulting in a better experience for your users.
The post-hydrate
strategy is ideal for cases where you want to make sure a script loads early without impacting your site’s time to interactive.
Idle strategy
The idle
strategy is similar to post-hydrate
in that it loads after hydration, with the difference being idle
will tell the browser to load the script when the main thread is free.
This means that if your page is doing other crucial work such as DOM manipulations or other calculations that occupy the main thread, your script will wait until after that work is complete to start loading.
The idle
strategy is ideal for cases where you want to ensure a script loads in a way that does not compete with other work being done on the main thread.
Off main thread strategy (experimental)
The off-main-thread
strategy, unlike post-hydrate
and idle
, loads your script in a web worker via Partytown.
This means that the burden of evaluation of your script is no longer the concern of the main thread, freeing it up to take care of other crucial tasks.
Note - Due to Partytown’s status as beta software, the
off-main-thread
strategy is considered experimental. It is subject to certain limitations and may require more configuration than other loading strategies depending on your use case.
Here is an example configuring the <Script>
component with the off-main-thread
strategy to load Google Analytics:
Forward collection
Gatsby will collect all off-main-thread
scripts on a page, and automatically merge any Partytown forwarded events defined via the forward
property into a single configuration for each page:
The forward
property is the only Partytown-specific property that is handled by the <Script>
component.
Proxy configuration
All URLs provided to the Gatsby <Script>
component with the off-main-thread
strategy are proxied by Gatsby to /__third-party-proxy?url=${YOUR_URL}
.
The reason for this is many third-party scripts require a proxy to work in Partytown, so Gatsby includes built-in proxy functionality to make this easier.
To keep the proxy secure, you must define the absolute URLs you want proxied in your Gatsby config with the partytownProxiedURLs
key. If you do not do this, the the request will 404.
Here’s how you would do that for the Google Analytics example above:
This works out of the box when running your site via gatsby develop
, gatsby serve
and Gatsby Cloud.
Hosting on other providers requires support for Gatsby’s createRedirect
action to rewrite requests from /__third-party-proxy?url=${YOUR_URL}
to YOUR_URL
with a 200 status code. You may need to check with your hosting provider to see if this is supported.
Resolving URLs
You can leverage Partytown’s vanilla config to handle Partytown-specific behavior in your off-main-thread
scripts. One such option is resolveUrl
, which allows you to modify URLs handled by Partytown.
One example of a use case for resolveUrl
is when using tag manager scripts such as Google Tag Manager. These scripts are challenging to use with Partytown since they contain other scripts that make other requests that may or may not need to be proxied depending on the CORS setting. In this scenario you can use resolveUrl
to handle those child script URLs.
Here’s an example using Google Tag Manager to load Google Analytics (Universal Analytics in this case):
Note - This assumes you have set up Google Tag Manager to use Universal Analytics in the Google Tag Manager web application.
First you load your Google Tag Manager (GTM) script and send an initialization event:
Then you define resolveUrl
in Partytown’s vanilla config to handle the Google Analytics script loaded by Google Tag Manager:
Lastly, you need to add the Google Analytics URL to partytownProxiedURLs
so that Gatsby knows the URL is safe to proxy:
At this point both your Google Tag Manager and Google Analytics scripts should load successfully in your site.
Debugging
You can also leverage Partytown’s vanilla config to enable debug mode for your off-main-thread scripts:
You may need to adjust your dev tools to the verbose log level in order to see the extra logs in your console.
Limitations
By leveraging Partytown, scripts that use the off-main-thread
strategy must also be aware of the limitations mentioned in the Partytown documentation. While the strategy can be powerful, it may not be the best solution for all scenarios.
In addition, there are other limitations that require upstream changes from Partytown to enable:
- The
onLoad
andonError
callbacks are not supported. See discussion #199 in the Partytown repo. - Scripts load only on server-side rendering (SSR) navigation (e.g. regular
<a>
tag navigation), and not on client-side rendering (CSR) navigation (e.g. Gatsby<Link>
navigation). See issue #74 in the Partytown repo.
Usage in Gatsby SSR and Browser APIs
The Gatsby <Script>
component can also be used in the following Gatsby SSR and Gatsby Browser APIs:
wrapPageElement
wrapRootElement
Note - If you use one of these APIs, it is recommended that you implement it both in Gatsby SSR and Gatsby Browser. A common pattern is to define a single function that you import and use in both files.
Here’s an example using wrapPageElement
in both Gatsby SSR and Gatsby Browser without duplicating your code:
onLoad
and onError
callbacks
Scripts with sources loaded with the post-hydrate
or idle
strategies have access to two callbacks:
onLoad
- Called once the script has loadedonError
- Called if the script failed to load
Note - Inline scripts and scripts using the
off-main-thread
strategy do not support theonLoad
andonError
callbacks.
Here is an example using the callbacks:
Duplicate scripts (scripts with the same id
or src
attributes) will execute onLoad
and onError
callbacks despite not being injected into the DOM.
Loading scripts dependently
Access to the onLoad
and onError
callbacks also enables the ability to load scripts dependently. Here’s an example showing how to load the second script after the first: