Expert guidance for building Google Tag Manager custom templates using sandboxed JavaScript. Use when creating custom tag templates, custom variable templates, server-side client templates, converting regular JavaScript to sandboxed JS, debugging template code, writing template tests, publishing to the Community Template Gallery, working with .tpl template files, or using sandboxed JavaScript APIs like require(), sendPixel, injectScript, and other GTM template APIs.
/plugin marketplace add henkisdabro/wookstar-claude-code-plugins/plugin install gtm-suite@wookstar-claude-code-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/example_asset.txtassets/tag-template-boilerplate.tplassets/variable-template-boilerplate.tplreferences/custom-templates-guide.mdreferences/sandboxed-javascript-api.mdreferences/template-examples.mdreferences/template-testing.mdThis skill provides comprehensive expertise for building Google Tag Manager custom templates using sandboxed JavaScript. Master template structure, sandboxed JavaScript APIs, permissions, testing, and publishing to the Community Template Gallery.
Invoke this skill when:
Sandboxed JavaScript is a restricted subset of JavaScript used in GTM custom templates. It provides security by limiting what code can execute while offering safe APIs for common operations.
Key Differences from Regular JavaScript:
// Import required APIs
const sendPixel = require('sendPixel');
const logToConsole = require('logToConsole');
const encodeUriComponent = require('encodeUriComponent');
// Access template configuration
const endpoint = data.endpoint;
const eventName = data.eventName;
// Execute template logic
const url = endpoint + '?event=' + encodeUriComponent(eventName);
sendPixel(url, data.gtmOnSuccess, data.gtmOnFailure);
Define Template Info
Configure Template Parameters
Write Sandboxed JavaScript Code
Set Permissions
Write Tests
Simple Pixel Tag:
const sendPixel = require('sendPixel');
const encodeUriComponent = require('encodeUriComponent');
const pixelUrl = data.pixelUrl +
'?id=' + encodeUriComponent(data.pixelId) +
'&event=' + encodeUriComponent(data.eventName);
sendPixel(pixelUrl, data.gtmOnSuccess, data.gtmOnFailure);
HTTP Request Tag:
const sendHttpRequest = require('sendHttpRequest');
const JSON = require('JSON');
const postBody = JSON.stringify({
event: data.eventName,
userId: data.userId
});
const options = {
headers: {'Content-Type': 'application/json'},
method: 'POST'
};
sendHttpRequest(data.endpoint, options, postBody)
.then(data.gtmOnSuccess)
.catch(data.gtmOnFailure);
Script Injection Tag:
const injectScript = require('injectScript');
const queryPermission = require('queryPermission');
const url = 'https://example.com/script.js';
if (queryPermission('inject_script', url)) {
injectScript(url, data.gtmOnSuccess, data.gtmOnFailure);
} else {
data.gtmOnFailure();
}
Variable templates return a value that can be used in other GTM configurations.
Cookie Variable:
const getCookieValues = require('getCookieValues');
const cookieName = data.cookieName;
const cookies = getCookieValues(cookieName);
if (cookies && cookies.length > 0) {
return cookies[0];
}
return data.defaultValue || '';
LocalStorage Variable:
const localStorage = require('localStorage');
const key = data.storageKey;
const value = localStorage.getItem(key);
return value || data.defaultValue;
Custom JavaScript Variable:
const makeTableMap = require('makeTableMap');
const makeNumber = require('makeNumber');
// Convert table to lookup map
const lookupTable = makeTableMap(data.table, 'key', 'value');
// Perform lookup
const inputValue = data.inputVariable;
return lookupTable[inputValue] || data.defaultValue;
Data Type Conversion:
const makeInteger = require('makeInteger');
const makeNumber = require('makeNumber');
const makeString = require('makeString');
const num = makeNumber('123.45'); // 123.45
const int = makeInteger('123.45'); // 123
const str = makeString(123); // '123'
Network APIs:
const sendPixel = require('sendPixel');
const sendHttpRequest = require('sendHttpRequest');
const injectScript = require('injectScript');
// Pixel
sendPixel(url, onSuccess, onFailure);
// HTTP Request
sendHttpRequest(url, options, body)
.then(onSuccess)
.catch(onFailure);
// Script injection
injectScript(url, onSuccess, onFailure);
Storage APIs:
const getCookieValues = require('getCookieValues');
const setCookie = require('setCookie');
const localStorage = require('localStorage');
// Cookies
const cookies = getCookieValues('cookieName');
setCookie('name', 'value', {
domain: 'example.com',
path: '/',
'max-age': 3600
});
// LocalStorage
const value = localStorage.getItem('key');
localStorage.setItem('key', 'value');
Utility APIs:
const encodeUri = require('encodeUri');
const encodeUriComponent = require('encodeUriComponent');
const decodeUri = require('decodeUri');
const decodeUriComponent = require('decodeUriComponent');
const JSON = require('JSON');
const Math = require('Math');
const Object = require('Object');
// URL encoding
const encoded = encodeUriComponent('hello world');
// JSON
const obj = JSON.parse('{"key":"value"}');
const str = JSON.stringify({key: 'value'});
// Math
const random = Math.random();
const rounded = Math.round(3.7);
DOM APIs (Limited):
const callInWindow = require('callInWindow');
const copyFromWindow = require('copyFromWindow');
// Call window function
callInWindow('functionName', arg1, arg2);
// Copy from window
const gaData = copyFromWindow('ga');
Every API requires explicit permission configuration. Permissions define what URLs, cookies, or data the template can access.
sendPixel Permission:
{
"instance": {
"key": {"publicId": "send_pixel", "versionId": "1"},
"param": [{
"key": "allowedUrls",
"value": {"type": 1, "string": "specific"},
"list": [
{"type": 1, "string": "https://example.com/*"}
]
}]
}
}
get_cookies Permission:
{
"instance": {
"key": {"publicId": "get_cookies", "versionId": "1"},
"param": [{
"key": "cookieAccess",
"value": {"type": 1, "string": "specific"},
"list": [
{"type": 1, "string": "session_id"},
{"type": 1, "string": "user_*"}
]
}]
}
}
Best Practice: Use the most restrictive permissions possible. Avoid "any" when you can specify exact URLs or cookie names.
// Test successful execution
scenarios:
- name: Tag fires successfully
code: |-
const mockData = {
endpoint: 'https://example.com/api',
eventName: 'test_event'
};
runCode(mockData);
assertApi('gtmOnSuccess').wasCalled();
assertApi('sendHttpRequest').wasCalledWith(
'https://example.com/api',
assertThat.objectContaining({method: 'POST'})
);
// Mock API returns
mock('getCookieValues', (name) => {
if (name === 'session_id') {
return ['abc123'];
}
return [];
});
// Test with mock
const mockData = {cookieName: 'session_id'};
let result = runCode(mockData);
assertThat(result).isEqualTo('abc123');
❌ Regular JavaScript (won't work):
// Direct DOM access
document.getElementById('element');
// Direct window access
window.dataLayer.push({});
// XMLHttpRequest
const xhr = new XMLHttpRequest();
✅ Sandboxed JavaScript (will work):
// Use callInWindow
const callInWindow = require('callInWindow');
callInWindow('dataLayer.push', {event: 'custom'});
// Use sendHttpRequest
const sendHttpRequest = require('sendHttpRequest');
sendHttpRequest(url, {method: 'GET'})
.then(data.gtmOnSuccess)
.catch(data.gtmOnFailure);
const sendHttpRequest = require('sendHttpRequest');
const logToConsole = require('logToConsole');
sendHttpRequest(data.endpoint)
.then(response => {
logToConsole('Success:', response);
data.gtmOnSuccess();
})
.catch(error => {
logToConsole('Error:', error);
data.gtmOnFailure();
});
const makeNumber = require('makeNumber');
const getType = require('getType');
// Validate input
if (getType(data.value) === 'undefined') {
data.gtmOnFailure();
return;
}
// Convert and validate
const numValue = makeNumber(data.value);
if (numValue === undefined) {
logToConsole('Invalid number');
data.gtmOnFailure();
return;
}
// Continue with valid data
data.gtmOnSuccess();
// Text input
{
"type": "TEXT",
"name": "apiKey",
"displayName": "API Key",
"simpleValueType": true,
"valueValidators": [
{"type": "NON_EMPTY"},
{"type": "REGEX", "args": ["^[a-zA-Z0-9]{32}$"]}
]
}
// Select dropdown
{
"type": "SELECT",
"name": "eventType",
"displayName": "Event Type",
"selectItems": [
{"value": "pageview", "displayValue": "Pageview"},
{"value": "event", "displayValue": "Event"}
],
"simpleValueType": true
}
// Checkbox
{
"type": "CHECKBOX",
"name": "enableDebug",
"checkboxText": "Enable Debug Logging",
"simpleValueType": true,
"defaultValue": false
}
// Group
{
"type": "GROUP",
"name": "advancedSettings",
"displayName": "Advanced Settings",
"groupStyle": "ZIPPY_CLOSED",
"subParams": [
// Nested fields here
]
}
Complete Template Info
Add Comprehensive Tests
Document Template
Submit for Review
This skill includes ready-to-use template boilerplates:
Copy these files and customize for your specific use case.
This skill includes comprehensive reference documentation:
Search references for specific APIs:
grep -r "sendHttpRequest" references/
grep -r "permissions" references/
grep -r "testing" references/
Import API: const apiName = require('apiName');
Success/Failure: Always call data.gtmOnSuccess() or data.gtmOnFailure()
Permissions: Every API requires explicit permission configuration
Testing: Use runCode(mockData) and assertions
Debugging: Use logToConsole() with debug environment permission
Use when working with Payload CMS projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.