Custom Code Injection: When, Where, and How

You need to add a custom font to a Squarespace site. Or load a third-party script. Or add CSS that only applies to one specific page. Squarespace gives you four places to inject code. Pick the wrong one and your site either breaks or runs inefficiently. Pick the right one and everything just works.

Here's how to choose and use them correctly.

The Four Places to Inject Code

Squarespace offers four distinct injection points. Each serves a different purpose.

Custom CSS (Design > Custom CSS). This isn't technically "code injection" but it's where 95% of your CSS should live. You've already seen this in the previous articles. It's compiled, minified, and delivered as part of the main stylesheet. Use this by default for any CSS that applies to the whole site.

Header Code Injection (Design > Website Tools > Code Injection > Header tab). This runs in the <head> tag, before the page starts rendering. Content loads after this runs. Use this for critical scripts, fonts, or styles that need to be in place before anything displays.

Footer Code Injection (Design > Website Tools > Code Injection > Footer tab). This runs just before the closing </body> tag, after all page content has loaded. Use this for analytics, tracking, non-critical scripts, and chat widgets.

Page-specific Code Injection (On any page, click the Settings gear icon > Advanced > Code Injection). This runs only on that specific page, in addition to header and footer injections. Use this for page-specific styles, scripts, or metadata.

Each one loads in a specific order and affects performance differently.

The Decision Framework

When you need to add code, ask these questions in order:

Is this CSS that applies site-wide? Use Custom CSS. Always. It's the most performant and the easiest to maintain.

Is this CSS that only applies to one page? Use page-specific Code Injection, in a style tag:

<style>
  .unique-page-section {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    padding: 3rem;
  }
</style>

Wrap it in a <style> tag, add it to that page's Code Injection area, and you're done. This CSS doesn't bloat your global stylesheet.

Is this a script that needs to run before the page renders? Use header Code Injection. Examples: Typekit fonts (though Squarespace has better font handling now), critical third-party scripts, things that prevent flash of unstyled content.

Is this a script that can wait until after the page loads? Use footer Code Injection. Examples: analytics, chat widgets, ad networks, lazy-loading libraries.

Is this code that only applies to one page and can wait until after the page loads? Use page-specific Code Injection. This is the most targeted option.

How Squarespace Loads Code

Knowing the load order helps you understand why something might not work.

Order of execution:

  1. Header Code Injection runs

  2. Page HTML and CSS (including Custom CSS) loads

  3. Footer Code Injection runs

  4. Page-specific Code Injection runs (if on a page with it)

This order matters. If you're trying to select an element in footer Code Injection, that element needs to exist in the HTML first. It will, because the page has already loaded. But if you're doing something in header Code Injection, the DOM might not be ready yet.

A practical example: adding a loading message before critical resources load. You'd put this in header Code Injection:

<script>
  document.documentElement.innerHTML = '<div class="loading">Loading...</div>' + document.documentElement.innerHTML;
</script>

This runs first, displays a message, then the page renders over it. If you tried this in footer Code Injection, the page would already be visible.

Adding Third-Party Scripts Safely

This is where code injection gets tricky. Third-party scripts can be fragile, and if you load them wrong, they break your site or bloat performance.

Analytics (Google Analytics, Hotjar, Mixpanel, etc.).

These go in footer Code Injection. They don't affect page rendering, and there's no reason to load them before the page is visible:

<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'GA_MEASUREMENT_ID');
</script>
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>

Replace GA_MEASUREMENT_ID with your actual ID. Footer injection is correct here.

Chat widgets (Intercom, Drift, Crisp, etc.).

Also footer Code Injection. They're non-critical, they load separately, and users don't need them instantly:

<script>
  window.intercomSettings = {
    api_base: "https://api-iam.intercom.io",
    app_id: "YOUR_APP_ID"
  };
</script>
<script async id="IntercomScript">(function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic('reattach_activator');ic('update',w.intercomSettings);}else{var d=document;var i=function(){i.c(arguments);};i.s=[];i.c=function(args){i.s.push(args);};w.Intercom=i;if(document.readyState==="complete"){i('boot',w.intercomSettings);}else if(w.attachEvent){w.attachEvent('onload',function(){i('boot',w.intercomSettings);});}else{w.addEventListener('load',function(){i('boot',w.intercomSettings);},false);}}})()</script>

Custom fonts (if not using Squarespace's font manager).

If you're loading fonts via header Code Injection (self-hosted or Google Fonts), put it in the header and load async:

<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">

Or for self-hosted fonts, use a @font-face rule in Custom CSS instead. That's cleaner:

@font-face {
  font-family: 'CustomFont';
  src: url('/path/to/font.woff2') format('woff2');
  font-weight: normal;
  font-display: swap;
}

body {
  font-family: 'CustomFont', sans-serif;
}

Conditional scripts (run only on specific pages).

Use page-specific Code Injection. This is the clean way to load a script only on certain pages:

<script>
  // This only runs on this page
  console.log('This page loaded a custom script');
  // Add page-specific functionality
</script>

Squarespace also exposes a global object that tells you what page you're on. You can check it:

<script>
  if (window.Squarespace && window.Squarespace.Context) {
    const pageId = window.Squarespace.Context.pageId;
    if (pageId === 'YOUR_PAGE_ID') {
      // Run code only on this page
    }
  }
</script>

Page-Specific CSS vs Page-Specific Code Injection

There's a distinction worth understanding. You can add CSS to a single page in two ways:

Add it to Custom CSS with a page-specific selector. If Squarespace gives the page a unique class or ID, you can use that:

/* In Custom CSS, this applies everywhere but only affects the about page */

.page[data-page-id='PAGE_ID'] .section-header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

Add a style tag to that page's Code Injection area.

<style>
  .section-header {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  }
</style>

The second approach is simpler and loads less CSS on pages that don't need it. But the first approach keeps all your CSS in one place. Choose based on how much CSS you're adding and how many pages need custom styling.

For a single page with a few CSS rules, page-specific Code Injection is cleaner. For five pages with similar customizations, Custom CSS with page-specific selectors is easier to maintain.

Code Injection vs Code Blocks

Squarespace also has Code Blocks, which you drag into pages like any other content block. These are different from Code Injection.

Use Code Blocks when: You want content (text, HTML, a widget) to appear in a specific place on the page, surrounded by other content. Code blocks are visible, contentful elements.

Use Code Injection when: You're loading scripts, styles, or functionality that shouldn't be visible content. Code injection is behind the scenes.

They serve different purposes. Don't confuse them. If you're adding a chat widget, use Code Injection (footer). If you're adding an embedded video player in the middle of a page, use a Code Block.

Performance Implications

Every script you add slows down your site, even slightly. Header injection is slower than footer injection because it runs before the page renders. Third-party scripts are slower than native JavaScript because they load from external servers.

Keep these principles in mind:

Load as late as possible. If a script doesn't need to run before the page is visible, load it in the footer, not the header. Save header injection for truly critical code.

Load asynchronously when possible. Add async to script tags:

<script async src="https://example.com/script.js"></script>

This tells the browser to load the script in parallel with other resources, not block on it.

Use deferred loading for non-critical scripts. Add defer to scripts that can wait until the page has loaded:

<script defer src="https://example.com/script.js"></script>

Avoid loading multiple versions of the same library. If you're loading jQuery for a custom script, make sure the client site isn't already loading jQuery elsewhere. Duplicate libraries waste bandwidth and cause conflicts.

Consider removing unused code injection. Audit your header and footer injection areas every few months. Remove scripts that aren't needed anymore. A chat widget for a client who no longer uses it is just slowing down the site.

Organizing Code Across Multiple Injections

If a client site has multiple code injection areas (custom CSS, header injection, footer injection, page-specific injections), it gets messy fast. Here's how to keep it organized:

In Custom CSS, add a table of contents at the top. See the first article for examples. This applies to code injection too. If you have multiple code injection areas, document what's in each:

/*
   HEADER CODE INJECTION
   - Google Fonts
   - Critical styles for hero section

   FOOTER CODE INJECTION
   - Google Analytics
   - Intercom chat widget
   - Drift widget

   PAGE-SPECIFIC INJECTIONS
   - /about page: custom hero styling
   - /services page: service comparison script
*/

Keep this comment in your Custom CSS as a manifest.

Use comments in each injection area to explain why the code is there.

/* Header Code Injection */

<!--
  Google Fonts for custom typography
  Used in: Custom CSS with @import fallback
  Can be removed if: Client switches to standard fonts
-->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">

<!--
  Preventing flash of unstyled content while fonts load
  Hides elements until google fonts loads
-->
<script>
  document.documentElement.classList.add('fonts-loading');
</script>

Version your injected code the same way you version Custom CSS. Add a date when you last updated it:

<!--
  FOOTER CODE INJECTION
  Last updated: 2025-03-15

  Contains:
  - Google Analytics (GA_ID)
  - Hotjar (HOTJAR_ID)
  - Custom event tracking for form submissions
-->

Common Mistakes and How to Avoid Them

Putting CSS in footer Code Injection. Don't. It creates a flash of unstyled content (FOUC) as the page renders before the CSS loads. Use Custom CSS or header injection for styles.

Loading the same script twice. If you add a library in header Code Injection and it's also included somewhere else, you're loading it twice. Check for this. Some third-party code loads its own dependencies. Make sure you're not duplicating.

Using hardcoded URLs instead of relative paths. If you inject code that references a file with a hardcoded domain, it breaks when the site moves or changes domains.

/* Bad */
<script src="https://oldsite.com/js/script.js"></script>

/* Better */
<script src="/js/script.js"></script>

Adding too much code to header injection. Header injection should be minimal. Every kilobyte there delays page rendering. Move anything non-critical to footer.

Forgetting to test on mobile. A script that works on desktop might break on mobile due to viewport differences or touch event handling. Always test on actual devices or device emulation.

Not handling missing elements gracefully. If you inject JavaScript that selects an element that doesn't exist on all pages, it throws an error and potentially breaks other scripts. Always check if an element exists before trying to manipulate it:

<script>
  const targetElement = document.querySelector('.hero-section');
  if (targetElement) {
    targetElement.classList.add('custom-style');
  }
</script>

Real Examples

Example 1: Adding a custom font via code injection

In header Code Injection, add the font file or Google Fonts reference:

<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&display=swap" rel="stylesheet">

Then in Custom CSS, use it:

h1, h2, h3 {
  font-family: 'Playfair Display', serif;
}

Example 2: Page-specific styles for the contact page

On the contact page only, go to page settings, Code Injection section, and add:

<style>
  .sqs-form input,
  .sqs-form textarea {
    border-radius: 8px;
    border: 2px solid #667eea;
    padding: 0.75rem;
  }

  .sqs-form button {
    background: #667eea;
    color: white;
    border: none;
    padding: 0.75rem 2rem;
    border-radius: 8px;
    cursor: pointer;
  }
</style>

This applies only to that page's form elements.

Example 3: Loading a script only on specific pages

On a pricing page, add to Code Injection:

<script>
  // Load comparison script only on pricing page
  const script = document.createElement('script');
  script.src = 'https://example.com/price-compare.js';
  document.body.appendChild(script);
</script>

This is cleaner than adding the script globally and checking which page you're on.

The Rule of Thumb

When choosing where to put code, think about three things: timing (when does it need to run), scope (which pages does it affect), and performance (how much does it cost).

Default to Custom CSS for global styles. Use footer injection for scripts that don't need to load early. Use header injection only for critical code. Use page-specific injection for anything that only affects one page.

Everything else is exception handling.

Related Reading

If you found this useful, these might be worth your time too:

Tools That Help

Chrome Extension can help with the workflows discussed in this article.

Want to go deeper? The Squarehead Advanced Course covers these topics and more across 11 structured modules.

Dave Hawkins // Made by Dave

As a top tier Squarespace Expert and founder of Made by Dave, I bring over 10 years of Squarespace experience and 600+ bespoke website launches. Our process combines consultancy, design, project management and development for a collaborative and efficient experience with clients like you. Whether you need a new website or updates for your existing site, we'll help you get up and running.

https://madebydave.org
Previous
Previous

Backing Up Your Squarespace Custom Code (Because You Should)

Next
Next

Information Architecture: The Skill That Separates Good Designers from Great Ones