-1

In a Gatsby.js project, is there any way to inject raw html inside the <head></head> tag of every page? I'm receiving a string of html for tracking (inline and external script tags, link tags and meta tags) that I just need to dump into the head tag.

Edit: Here is an example of what the html looks like that I'll receive (due to restrictions of the environment I'm working in, I'm not able to edit the html string):

<script src="//sometracking.com/script.js" async></script>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','TAGID');</script>
<!-- End Google Tag Manager -->
<link rel="stylesheet" type="text/css" href="https://somefont.com/stylesheet.css" />
<link href="~/another/stylesheet.css" type="text/css" rel="stylesheet" />
<link href="~/more/styles.css" type="text/css" rel="stylesheet" />
<script language="javascript" type="text/javascript" src="~/vendor/javascript.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="format-detection" content="telephone=no">
<meta name="apple-itunes-app" content="app-id=123456789">
<meta name="google-play-app" content="app-id=com.blah.blah">
<link rel="apple-touch-icon" sizes="180x180" href="~/icon.png" />
..
  • I've tried using react-helmet (requires either a: properties passed to the meta prop or b: the script/meta/link tags to be JSX as children)

  • I've tried using the onPreRenderHTML API within gatsby-ssr.js. (similar problem where it expects jsx instead of a string)

      // THIS RENDERS THE HTML AS TEXT IN THE BODY TAG
    
      const headScripts = `<script type="text/javascript">alert("tracking stuff");</script>`;
      exports.onPreRenderHTML = ({ getHeadComponents, replaceHeadComponents }) => {
          replaceHeadComponents([...getHeadComponents(), headScripts]);
      };
    
  • Plugins like gatsby-plugin-google-tagmanager are not an option as the tracking html comes in as one big string

Any insight would be greatly appreciated!

ksb1986
  • 29
  • 7
  • What's the issue when trying `Helmet` approach? – Ferran Buireu Sep 10 '21 at 05:10
  • The issue is that the tracking string that is given to me already has the opening and closing script/meta/link tags included. – ksb1986 Sep 10 '21 at 15:24
  • I added an edit in the original post to show an example of the html I have to put in. Dumping that inside the `` tag does not work. – ksb1986 Sep 10 '21 at 15:39
  • Does this answer your question? [Adding script tag to React/JSX](https://stackoverflow.com/questions/34424845/adding-script-tag-to-react-jsx) – Liam Sep 10 '21 at 15:40
  • That said, the correct way, without "dumping in code", to do this is to use the correct plugin, e.g. [gatsby-plugin-google-tagmanager](https://www.gatsbyjs.com/plugins/gatsby-plugin-google-tagmanager/) – Liam Sep 10 '21 at 15:42
  • *Plugins like gatsby-plugin-google-tagmanager are not an option as the tracking html comes in as one big string*. That's only the quick start. You can 100% add this same functionality using the plugin. It just requires a little more understanding. – Liam Sep 10 '21 at 15:44
  • @Liam, unfortunately no that does not answer my question. Due to restrictions of the environment I'm working in, "dumping in code" is my only option. I do not have the ability to edit the html string before it comes to me or parse out the src to build my own scripts. So the "Adding script tag to React/JSX" resource will not work for me. Thanks though. – ksb1986 Sep 10 '21 at 15:49
  • @Liam, how can that plugin _100% add this same functionality_? I'm open to any suggestions to increase my understanding. – ksb1986 Sep 15 '21 at 21:39

1 Answers1

-1

I solved this by creating a custom html.js file (Gatsby documentation here) and using html-react-parser.

First I copied .cache/default-html.js to src/html.js in order to modify the root html document that Gatsby uses. Then I used the html-react-parser package to place the tracking html that is given to me into the head.

My modifications to the html.js file are indicated by the ADDED comments below

import React from "react";
import PropTypes from "prop-types";
import parse from "html-react-parser"; // ADDED
import getTrackingHtml = from './myCustomUtils'; // ADDED

export default function HTML(props) {
    const trackingHtml = getTrackingHtml(); // ADDED

    return (

        <html {...props.htmlAttributes}>
            <head>
                <meta charSet="utf-8" />
                <meta httpEquiv="x-ua-compatible" content="ie=edge" />
                <meta
                    name="viewport"
                    content="width=device-width, initial-scale=1, shrink-to-fit=no"
                />
                {props.headComponents}
                {parse(trackingHtml)} {/* ADDED */}
            </head>
            <body {...props.bodyAttributes}>
                {props.preBodyComponents}
                <div
                    key={"body"}
                    id="___gatsby"
                    dangerouslySetInnerHTML={{ __html: props.body }}
                />
                {props.postBodyComponents}
            </body>
        </html>
    );
}

HTML.propTypes = {
    htmlAttributes: PropTypes.object,
    headComponents: PropTypes.array,
    bodyAttributes: PropTypes.object,
    preBodyComponents: PropTypes.array,
    body: PropTypes.string,
    postBodyComponents: PropTypes.array,
};

(Note: "Anything you render in the html.js component will not be made “live” in the client like other components" -Gatsby Documentation)

ksb1986
  • 29
  • 7