How to save UTM parameters in Shopify cart using a theme extension - encountering a syntax error

I’m developing a theme extension to save UTM tracking parameters in the Shopify cart. This extension should activate when the page loads and check the URL parameters. If it detects any values for utm_source, these should be appended to the cart attributes, ensuring they persist even if the URL changes after that.

Below is the code I’m currently working with:

{% comment %}
  Script designed to gather marketing parameters on shop entry
{% endcomment %}

<script>
    const cartContents = {{ cart.attributes }}
    if (!cartContents.UTMData) cartContents.UTMData = []
    const searchParams = new URLSearchParams(window.location.search);
    for (const [key, value] of searchParams.entries()) {
        if (key === "utm_source" && !cartContents.UTMData.includes(value)) {
            cartContents.UTMData.push(value)
            console.log(cartContents, 'updated cart attributes')
        }
    }
    fetch(window.Shopify.routes.root + 'cart/update.js', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            attributes: cartContents
        })
    })
    .then(function(result) {
        return result.json();
    })
    .then(function(output) {
        console.log(output);
    })
    .catch(function(error) {
        console.error(error);
    });
</script>

{% schema %}
    {
        "name": "UTMTracking",
        "target": "body",
        "settings": []
    }
{% endschema %}

I’m facing this JavaScript error: Uncaught SyntaxError: Unexpected token '=>'. What might be causing this syntax problem?

The problem is {{ cart.attributes }} spits out raw Liquid data, which breaks JavaScript syntax when the browser tries to parse it. I ran into this exact issue building UTM tracking for a client. Beyond fixing the JSON formatting (like others said), you’re treating cart attributes like you can mutate them directly - but they’re immutable server-side data. You need to build a fresh object for the API call. Try this instead: const cartContents = { ...{{ cart.attributes | json }}, UTMData: {{ cart.attributes.UTMData | json }} || [] }. Also, add a check to skip the API call if the UTM parameter already exists in cart attributes. Your script runs on every page load, so you’ll hammer the API otherwise.

your cart.attributes is spitting out malformed JSON that breaks in the browser. classic Shopify Liquid issue. try wrapping it with {{ cart.attributes | json | escape }} or just initialize an empty object and skip the liquid output since you’re checking for UTMData anyway.

That syntax error happens because Shopify’s {{ cart.attributes }} liquid object breaks JavaScript when it hits the browser. Cart attributes with complex data or special characters mess up the parsing - I dealt with this exact problem last year on a tracking project. The issue is cart.attributes spits out properties that aren’t valid JavaScript identifiers, or quotes that don’t get escaped properly. Don’t embed the liquid object directly. Use JSON.parse() with the json filter instead: const cartContents = JSON.parse('{{ cart.attributes | json }}'). This formats everything as proper JavaScript and handles special characters. Also throw your script in a try-catch block so parsing errors don’t break everything while you’re developing.