DEV Community

Bruce Axtens
Bruce Axtens

Posted on

Using UrlRewrite to inject scripts into web pages

Today I learned that there's a gotcha when injecting script into pages using IIS's UrlRewrite: JavaScript scripts with braces.

Braces have a purpose in rewrite rules, to introduce those things captured in the match clause. Notice in the following outbound rule, that the text captured by the regular expression in the match pattern is reinserted in the action.

<rule name="Inject GTM After /TITLE" preCondition="ResponseIsHtml1" enabled="true" stopProcessing="true">
<match filterByTags="None" pattern="&lt;/title>" />
<action type="Rewrite" value="{R:0}&lt;!-- Google Tag Manager (noscript) --> &lt;noscript>&lt;iframe src=&quot;https://www.googletagmanager.com/ns.html?id=GTM-XXXX&quot; height=&quot;0&quot; width=&quot;0&quot; style='display:none;visibility:hidden'>&lt;/iframe>&lt;/noscript> &lt;!-- End Google Tag Manager (noscript) -->" />
</rule>
Enter fullscreen mode Exit fullscreen mode

So there we were trying to embed a GTM script into a page via a rewrite rule, viz

<rule name="Inject GTM After /TITLE" preCondition="ResponseIsHtml1" enabled="true">
<match filterByTags="None" pattern="&lt;/title>" />
<action type="Rewrite" value="{R:0}&lt;!-- Google Tag Manager --> &lt;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'?'&amp;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','GTM-XXXX');&lt;/script> &lt;!-- End Google Tag Manager -->" />
</rule>
Enter fullscreen mode Exit fullscreen mode

That looked like it would work but it does NOT as the JavaScript contains { and IIS's UrlRewrite tool immediately complains with a yellow box reading The rewrite provider " w[l]=w[l]||[];w[l].push( { 'gtm.start'" does not exist (note that it terminates at the : which would separate the usual R or C from the numeric qualifier.)

We tried swapping { with &#123; but that doesn't work well, giving us the following in the generated web page:

<!DOCTYPE HTML>
<html lang="en">
    <head><title>The Page</title><!-- Google Tag Manager --> <script>(function(w,d,s,l,i) &#123; w[l]=w[l]||[];w[l].push( &#123; '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','GTM-XXXX');</script> <!-- End Google Tag Manager -->
    <meta charset="UTF-8"/>
Enter fullscreen mode Exit fullscreen mode

Naturally, the browser's JavaScript interpreter complains about bad code.

What we finally ended up doing was to create a js file in another of our websites and then embed a reference to it in the rule, viz

<rule name="Inject GTM After /TITLE" preCondition="ResponseIsHtml1" enabled="true" stopProcessing="true">
<match filterByTags="None" pattern="&lt;/title>" />
<action type="Rewrite" value="{R:0}&lt;!-- Google Tag Manager --> &lt;script type=&quot;text/javascript&quot; src=&quot;https://sub.domain.com.au/js/GTM-XXXX.js&quot;>&lt;/script> &lt;!-- End Google Tag Manager -->" />
</rule>
Enter fullscreen mode Exit fullscreen mode

Maybe this is the better thing to do. It'll do for now.

Top comments (0)