If I add it an expression, the script is placed inside the top-level <form> tag, which conflicts with Google Tag Manager's click event listeners. In that case, clicks are not being registered.
What is the best way to place the script straight after the <body> tag? I can see the following options:
Feels a bit hacky.
3. Use the HTTPRequestHandler PostProcessingFilter action to replace <body ...> with <body><script>
In this case I'm not sure how to properly recognize the body tag and replace it such that all attributes are still there after replacing.
Any thoughts on what the best practice solution would be? Any downsides beside the ones I mentioned?
You covered pretty well all the possible ways.
Are you sure about 2. ? That is a strange behaviour.
It depends on the developer. 3 is the cleanest, but most old school web developers (pre-OS) will prefer 1.
To personal sites and other tags I'd accept going with 1, but I assume you're not using GTM for an internal site. To public sites, where you want to get visitors and really take advantage of analytics and advertising tools, I'd read carefully the Google sugestions and probably exclude 1. The thing is, search engines are getting smarter and can emulate a human when reading the site. Instead of reading html and building their version of the page, they wait for the onload action to execute before interpreting the final generated html as a page. So they will load the GTM and see your use of tags and its reasult on the final page. Google or not, do you trust any machine that much?
When that process is done it will be the same. Until then, I'd rather have my tags embedded server-side.