← Timeline

Jun 2026 · Creative

Custom success pages for ActiveCampaign forms

How to make ActiveCampaign inline forms redirect to your own thank-you page instead of the bare-bones, generic and ugly confirmation screen.

Another one from the “helping out my partner” stack…

She uses ActiveCampaign to set up sign-up forms for mailing lists, promotions and products. These forms are then embedded in her Wix site, as an <iframe> embed.

ActiveCampaign’s inline forms have an “On Submit → Open URL” option, but we have found that new subscribers still land on ActiveCampaign’s generic “Thanks for signing up!” confirmation page rather than the custom thank-you page she set up.

We raised this bug with ActiveCampaign over 12 months ago, but nothing seems to have been fixed, and thus it doesn’t seem like there will be a fix coming any time soon.

After a bit of troubleshooting, we came up with a workaround. Despite it feeling a bit “hacky” and not being the nicest thing in the world, it seems to work reliably without breaking tags, automations, etc.

Why the redirect fails

The ActiveCampaign inline embed works like this:

  1. On submit, it fires a JSONP request to proc.php?…&jsonp=true using a dynamically inserted <script> tag
  2. That script executes inside the iframe context (if you’re in one)
  3. On success, the JSONP response looks something like:
window.top.location.href = "https://yoursite.activehosted.com/f/confirm.php?id=…";

This lil’ nugget takes the subscriber to the “default” success page—not the one you’ve built and specified in ActiveCampaign’s form building tools.

Because that line runs before the _show_thank_you handler ever fires, even a correctly-configured “Open URL” setting (in ActiveCampaign) gets bypassed.

ActiveCampaign form setup

First, make sure the form itself is configured correctly:

  1. Website → Forms → open the form
  2. Options → On SubmitOpen URL
  3. Paste your full thank-you URL
  4. Save

The client-side override

Paste the Full Embed HTML that ActiveCampaign gives you into your page or HTML component as usual, then append the following script block after it. The order matters—this script wraps functions that the ActiveCampaign code has to define first.

That is, leave the stock ActiveCampaign embed script unchanged. Only add the override block at the end—i.e.

<script>
...ActiveCampaign embed code...
</script>
<script>
...the override script (below)...
</script>

Replace the text in https://yoursite.com/thank-you with your actual thank-you page URL.

<script>
(function () {
  const THANK_YOU_URL = 'https://yoursite.com/thank-you';
  const ERROR_GRActiveCampaignE_PERIOD_MS = 800; // time to let a delayed _show_error land before redirecting

  const redirectToThankYou = () => {
    (window.top || window).location.href = THANK_YOU_URL;
  };

  const acLoadScript = window._load_script;
  const acShowError = window._show_error;

  let submissionFailed = false;

  // CAPTCHA/validation failures from proc.php don't call _show_error
  // synchronously—see "CAPTCHA fails but thank-you shows anyway" below.
  // Hooking this directly is the reliable signal; checking the DOM at
  // onload time is not.
  window._show_error = function (...args) {
    submissionFailed = true;
    return acShowError?.apply(this, args);
  };

  window._show_thank_you = () => {
    redirectToThankYou();
  };

  window._load_script = (url, callback, isSubmit) => {
    if (isSubmit) {
      submissionFailed = false;
      return acLoadScript.call(this, url, () => {
        // Give a delayed _show_error time to arrive before deciding this
        // submission actually succeeded.
        setTimeout(() => {
          if (!submissionFailed) {
            redirectToThankYou();
          }
        }, ERROR_GRActiveCampaignE_PERIOD_MS);
        callback?.();
      }, isSubmit);
    }
    if (url && /confirm\.php|activehosted\.com\/f\//.test(url)) {
      redirectToThankYou();
      callback?.();
      return;
    }
    return acLoadScript.call(this, url, callback, isSubmit);
  };

  window._form_callback = () => {
    if (!submissionFailed) redirectToThankYou();
  };
})();
</script>

Additional notes

PiecePurpose
_load_script + isSubmitLets proc.php process the submission normally; waits a short grace period, then redirects only if _show_error hasn’t fired
_load_script + confirm.php URLIntercepts the JSONP response when it tries to navigate to ActiveCampaign’s confirmation page
_show_thank_youRedirects when ActiveCampaign calls its inline success handler
_form_callbackBelt-and-braces redirect at the end of success handling
window.topBreaks out of any iframe so the whole page navigates, not just the embed

Don’t skip proc.php

The submit flow calls:

_load_script('https://yoursite.activehosted.com/proc.php?' + serialized + '&jsonp=true', null, true);

That GET request is the submission to the ActiveCampaign system. Tags, automations, and webhooks all run when ActiveCampaign receives this request. The isSubmit branch in our override waits for proc.php to finish, then redirects. If you modify this script, never return early on isSubmit without calling acLoadScript—that will skip proc.php entirely and none of your ActiveCampaign actions will run. (Go on, ask me how I know this… 🙄)

Checklist for a new form

(Bonus Tip: How you can use Gmail + addresses for your testing.)

Troubleshooting

Still seeing ActiveCampaign’s generic confirmation page

Possible reasons:

Redirect works but only appears inside the iframe

Tags/automations/webhooks not firing

Mobile keyboard “Send”/“Go” submits, but nothing reaches ActiveCampaign

The confirm.php/activehosted.com/f/ check must run after the isSubmit check, not before. On some mobile flows, ActiveCampaign’s own submit call (isSubmit: true) can carry a URL matching that pattern. If the pattern check runs first, it short-circuits and redirects without ever calling acLoadScript—so proc.php never fires and the submission is silently dropped, even though the thank-you page still shows. Check isSubmit first, unconditionally, before testing the URL pattern (see script above).

CAPTCHA (or other validation) fails, but the thank-you page shows anyway

A failed CAPTCHA doesn’t call ActiveCampaign’s _show_error() synchronously. The failure response first reloads the reCAPTCHA widget (a separate, async _load_script call to Google’s API), and _show_error only fires once that finishes loading. By the time proc.php’s own script tag fires onload, the error hasn’t landed in the DOM yet—so checking for a ._form_error element at that exact moment is too early and will miss it every time.

The Fix: hook _show_error directly (it’s the reliable signal, not a DOM side-effect you have to poll for) and add a short grace period (a few hundred ms) before redirecting, so a delayed error has time to arrive and cancel it. See script above.

If you still see false-positive redirects, increase ERROR_GRActiveCampaignE_PERIOD_MS—reCAPTCHA’s API load time varies with network conditions.

This is a different bug from the mobile keyboard issue above. Both involve isSubmit, but this one happens in a normal browser as well as on mobile, and it needs timing/flag-based handling rather than a reordering of the existing checks.