Skip to content
HomeScripts/confetti-growth-celebration

Confetti on conversion

Draws a short canvas confetti burst when your thank-you trigger fires, shows a discount badge for five seconds, and pushes growth_milestone_unlocked to the dataLayer. Around 65 lines, no library.

Try it
Shows a worked example of the output, not a run against your account.
dataLayer
Nothing yet
GTM Custom HTML Tag (JavaScript)
<script>
(function() {
  function fireConfetti() {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: 'growth_milestone_unlocked',
      timestamp: new Date().toISOString()
    });

    var canvas = document.createElement('canvas');
    canvas.style.cssText = 'position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:999999;pointer-events:none;';
    document.body.appendChild(canvas);

    var ctx = canvas.getContext('2d');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    var colors = ['#16A34A', '#2563EB', '#F59E0B', '#EC4899', '#8B5CF6'];
    var particles = [];
    for (var i = 0; i < 100; i++) {
      particles.push({
        x: canvas.width / 2,
        y: canvas.height / 2 - 50,
        vx: (Math.random() - 0.5) * 16,
        vy: (Math.random() - 0.8) * 18,
        size: Math.random() * 8 + 5,
        color: colors[i % colors.length],
        gravity: 0.35,
        tilt: Math.random() * 10
      });
    }

    var frame = 0;
    function render() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      for (var j = 0; j < particles.length; j++) {
        var p = particles[j];
        p.x += p.vx;
        p.y += p.vy;
        p.vy += p.gravity;
        p.tilt += 0.1;
        ctx.fillStyle = p.color;
        ctx.fillRect(p.x, p.y, p.size, p.size * Math.cos(p.tilt));
      }
      frame++;
      if (frame < 160) requestAnimationFrame(render);
      else canvas.remove();
    }
    render();

    var badge = document.createElement('div');
    badge.style.cssText = 'position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:#16A34A;color:#fff;padding:14px 24px;border-radius:100px;box-shadow:0 10px 30px rgba(22,163,74,0.4);font-family:sans-serif;font-weight:600;font-size:14px;z-index:9999999;animation:fadeIn 0.3s ease;';
    badge.innerText = "🎉 Milestone Unlocked: 15% Consulting Discount Applied!";
    document.body.appendChild(badge);
    setTimeout(function() { badge.remove(); }, 5000);
  }

  window.__goodlabs_confetti = fireConfetti;
})();
</script>

How it works

  1. Dynamically mounts a full-viewport canvas with pointer-events: none.
  2. Spawns 100 squares with randomised velocity, colour and the same downward gravity.
  3. Animates on requestAnimationFrame for 160 frames, then removes the canvas. The discount badge stays 5 seconds.
  4. Pushes { event: 'growth_milestone_unlocked', perk: '15_percent_discount' }.

Step-by-step installation

  1. Create a Custom HTML tag in GTM with the snippet above.
  2. Set trigger to your Lead Form Success / Thank You trigger.
  3. Test in GTM Preview Mode.

Frequently asked questions

Can I trigger this on button clicks?

Point the tag at a Click trigger instead of the form-success one. Nothing in the code depends on which trigger fires it.

Need one of these adapted to your account?

We write Google Ads scripts, set up server-side GA4, and build the reporting that answers a specific question.