Passing data when loading an external JS script

Say you have to develop an embedded JavaScript widget and you would like to pass specific client data to your script. For example, the way Google passes options to the recaptcha script.

<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
    async defer>
</script>

As you can see in the example above, taken from the official Recaptcha V2 documentation, when the API is loaded it will automatically recover the values "explicit" for render and "onloadCallback" for onload.

But how does it do that? I was left wondering after I needed to implement a similar functionality myself. The answer is document.currentScript.

The MDN documentation for document.currentScript states the following:

The Document.currentScript property returns the <script> element whose script is currently being processed and isn't a JavaScript module.

It's important to note that this will not reference the <script> element if the code in the script is being called as a callback or event handler; it will only reference the element while it's initially being processed.

What does that mean?

Say you create your own script at yoursite.com/api/my_api.js and you tell people to include it like this:

<script src="https://yoursite.com/api/my_api.js?widget_color=blue"
></script>

When the script will be loaded and evaluated, document.currentScript will point to its DOM own node. This means you can do something like this in your code:

let api_script = document.currentNode;

let api_script_src = api_script.getAttribute('src');

In that moment, api_script_srcs value will be https://yoursite.com/api/my_api.js?widget_color=blue and from here you can recover the value blue for the widget_color parameter.

It's up to you on how to recover the value. One version would be to use the URLSearchParams object.

let api_script_src_url = new URL(api_script_src), 
    api_url_params = new URLSearchParams(api_script_src_url.search);

let widget_color = api_url_params.get('widget_color');
// will return "blue"

Any other options?

If passing that via the API's script URL is not an ok solution for you, an alternative would be to use custom tags. For example:

<script src="https://yoursite.com/api/my_api.js" data-color="blue"
></script>

In this scenario, the code to recover the value will look like this:

let api_script = document.currentNode;

let color = api_script.getAttribute('data-color');
// will return 'blue'

This method has the advantage that you do not need to encode and decode the params as URI components.

If you're building a widget and the solution described in this post is helpful, you might also want to check another one of my articles: How to create a web button unaffected by external CSS styles in which I describe how to use Shadow DOM.