Using ActionTag


ActionTag is an easy way to embed forms on any site. Much like Twitter Embedded Timelines, the idea is to use one line of JavaScript and one line of HTML to have a foolproof way to present a form that posts back to your database.


What is it?

ActionTag is our name for our embeddable forms functionality. Embeddable on any page on the web, it will:

  • Make an API call to retrieve that form’s definition (aka which fields should display)
  • Render a fully functional form to the screen
  • Pre-fill that form under certain circumstances
  • Handle submission of that form back to the server
  • Deal with behaviors that occur after submission such as:
    • Displaying another form (secondary ask, or daisy-chaining)
    • Showing a thank you message
    • Redirect to another URL

How to Find the Embed Code

The easiest way to use ActionTag on your own website is to use the embed codes provided inside the form builder. In Online Actions there is a “Link & Embed” button at the top of every step of the form builder, which is enabled once you have published your form. In EveryAction 7, you can find the embed code on the last step of the Online Page Manager (the step labeled “Published Page Info”).

Getting Started with Manually Embedding a Form

All that’s necessary to use ActionTag is to drop a special <div> tag on any page along with our JavaScript file. For example:

  <script type="text/javascript" src=""></script>
  <div class="ngp-form" data-form-url=""></div>

We use the class ngp-form to indicate that this is the place where the form should render.

NOTE: any use of ActionTag for processing payment information must be embedded in a TLS-secured page.

To specify which form to render, add the only other required data attribute, the data-form-url attribute, e.g. data-form-url="". Each form published has a unique id which can be used in this tag.

These are the simplest cases. Below are some more of the data attributes that can optionally be added to the tag to alter its behavior.

For users who draft emails for use in Targeted Email, a special merge field is available which auto-fills user contact data merge fields in an ActionTag form. To use this merge field, append contactdata={{ContactData}} to any URL which hosts an ActionTag form, and embed the resulting URL in the body of a Targeted Email. Doing so will cause the following merge data to be automatically merged in to when email receipients click through the URL in the email, and view the form:

  • First Name
  • Middle Name
  • Last name
  • Subscriber Email
  • Street Address
  • City
  • State or Province
  • Zip or Postal
  • Home Phone
  • Cell Phone
  • Work Phone
  • Employer
  • Occupation
  • Prefix
  • Suffix


  1. You create a form in Online Actions, and use ActionTag to embed it at
  2. You draft an email to your supporters.
  3. In the body of the email, you include the following URL:{{ContactData}}
  4. You paste the body of the email into Targeted Email, and send the email to your supporters.
  5. When Targeted Email generates the email, it prepares a special encoded string, specific to each supporter. This encoded string is merged in to the personalized email which each supporter receives. For example, supporter Jane Casey might receive an email with the URL
  6. Jane Casey, one of your supporters, receives the email and clicks the link.
  7. ActionTag displays the form from step 1.
  8. ActionTag reads the contactdata string, and merges Jane Casey’s data into the form display.

It is also possible to add contactdata alongside other parameters. For example, if you wanted to use the Targeted Email merge field for a record’s highest previous contribution to set the contribution amount on a form, defaulting to $3 if the record is a nondonor, then the url would look like this:{{HighestPreviousContribution or '3'}}&contactData={{ContactData}}.

What are Query Strings?

A query string is something you can add to the end of the URL your form lives at, e.g. Primarily, query string values are used to pre-fill values in the form. The general format is that the first bit is the name of the form field, followed by an equals sign and then whatever data you wish to pre-fill that form field with. ActionTag assumes US formats for all fields (phone, postal code, amounts, etc.).

The way to add these onto a form is that the first one needs to use a question mark, and other subsequent ones use an ampersand, e.g.


It is not advised to put PII in your URL via query strings, as that can expose personal information to services like Google Analytics, and instead we recommend using the Smartlinks functionality available in Targeted Email.

Query Strings

The following are available visible fields to be filled via Query Strings:

Name Parameter Sample Notes
AddressLine1 add1 add1=1250+Hancock+St.
AddressLine2 add2 add2=Ste.+202
Additional Contribution Value AdditionalContributionValue AdditionalContributionValue=25 Prefill the additional contribution amount on event forms only
Amount am am=5
AmountOptions amtOpts amtOpts=3,5,20.16,50,100 This sets the radio button options on a contribution page, enabling dynamic ask amounts. To select a particular contribution amount, use Amount
City ci ci=Boston
Cover Costs CoverCosts CoverCosts=true If the Cover Costs checkbox is enabled on the Contribution or Ticketed Event form, this query string checks that checkbox, adding the Cover Costs amount (configured in Online Actions) to the contribution amount selected by the donor.
Currency currency currency=EUR Works for Contribution forms that support international currencies; will not work for Ticketed Event forms
• Valid values include USD, GBP, CAD, and EUR
• Can be used in combination with am and amtOpts
• If currency is passed without am or amtOpts, passed currency will be selected and amounts on form will be converted
• If currency is passed with amtOpts, passed currency will be selected and amount options will be offered as passed
• If supporter then selects a new currency, amounts will be converted to selected currency
• If currency is passed with am, passed currency and amount will be selected
EmailAddress em
Employer ep ep=ACME Industries
Ethnicity ethn ethn=1,2,3 1 • Afghani
2 • Arab
3 • Asian Indian
4 • Bangladeshi
5 • Bhutanese
6 • Brazilian
7 • Chinese
8 • East African
9 • Filipino
10 • Haitian
11 • Hmong
12 • Indo Carribean
13 • Lao
14 • Nepali
15 • Pakistani
16 • Somali
17 • Sri Lankan
18 • Tibetan
19 • Vietnamese
20 • Latino
21 • Arabian
22 • Armenian
24 • East European
25 • Indian
26 • English (British)
27 • French
28 • German
29 • Hispanic (Spanish)
30 • Irish
31 • Italian
32 • Japanese
34 • Polish
35 • Native American
36 • Scottish
37 • Swedish
39 • Samoan
40 • Korean
42 • Tagalog (Filipino)
44 • Czechoslovakian
45 • Norwegian
46 • Dutch
47 • Greek
48 • Hungarian
49 • Middle Eastern
50 • Russian
51 • Ukrainian
52 • Welsh
54 • Bulgarian
55 • Burmese
56 • Cambodian
57 • Estonian
58 • Ethiopian
59 • Finnish
60 • Icelandic
61 • Indonesian
62 • Hebrew
64 • Latvian
65 • Lithuanian
66 • Malaysian
67 • Manx
68 • Portuguese
69 • Alaskan
71 • Swiss
72 • Thai
73 • Turkish
74 • Yugoslavian
75 • Danish
76 • African
77 • Hawaiian
78 • African American
81 • Asian
82 • Hispanic
83 • Mixed Ethnicity
85 • Other
86 • Persian
87 • Yemeni
88 • Egyptian
89 • Morrocan
90 • Lebanese
91 • Caucasian
93 • Chamorro
94 • Guamanian
95 • Mariana Islander
96 • Mien
97 • Bengali
98 • Chin
99 • Karen
101 • Mongolian
102 • Native Hawaiian/Pacific Islander
103 • Okinawan
104 • Singaporean
105 • Taiwanese
106 • Tongan
120 • Unknown
FacebookProfileUrl fb fb=
FirstName fn fn=John
Gender gen gen=1,2,3 1 • Androgynous
2 • Female
3 • Female to Male
4 • FTM
5 • Gender Fluid
6 • Gender Non-conforming
7 • Genderqueer
8 • Male
9 • Male to Female
10 • Man
11 • MTF
12 • Non-Binary
13 • Prefer Not to Say
14 • Questioning
15 • Trans
16 • Transgender
17 • Woman
18 • Agender
19 • Androgyne
20 • Bigender
21 • Butch
22 • Femme
23 • Gender Questioning
24 • Gender Variant
25 • Genderless
26 • Hijra
27 • Intersex
28 • Masc
29 • Neither
30 • Neutrois
31 • Non-Op
32 • Other
33 • Pangender
34 • Polygender
35 • Queer
36 • Transfeminine
37 • Transgender Female
38 • Transgender Male
39 • Transgender Man
40 • Transgender Person
41 • Transgender Woman
42 • Transmasculine
43 • Transsexual
44 • Transsexual Female
45 • Transsexual Male
46 • Transsexual Man
47 • Transsexual Person
48 • Transsexual Woman
49 • Two Spirit
54 • Cisgender Man
55 • Cisgender Woman
Home Country c c=US; c=CA
HomePhone hp hp=6175551234
IsRecurring r r=true Use true or false to set an exposed recurring checkbox to be checked or not, respectively.
LastName ln ln=Adams
MiddleName mn mn=Quincy
MobilePhone mp mp=6175551234
Occupation oc oc=President
PostalCode pc pc=02144
Preferred Language preflang preflang=2 1 • Bengali
2 • Cantonese
3 • English
4 • French
5 • Gujarati
6 • Hindi
7 • Japanese
8 • Korean
9 • Malayalam
10 • Mandarin
11 • Nepali
12 • Punjabi
13 • Russian
14 • Sinhalese
15 • Spanish
16 • Tagalog
17 • Tamil
18 • Tibetan
19 • Urdu
20 • Vietnamese
21 • Arabian
22 • Armenian
23 • Misc Asian
24 • Misc European
25 • Indian
26 • German
27 • Hispanic (Spanish)
28 • Italian
29 • Pakistani
30 • Polish
31 • Swedish
32 • Samoan
33 • Tagalog (Filipino)
34 • Chinese
35 • Czechoslovakian
36 • Norwegian
37 • Dutch
38 • Greek
39 • Hungarian
40 • Middle Eastern
41 • Bangladesh
42 • Bulgarian
43 • Burmese
44 • Cambodian
45 • Estonian
46 • Ethiopian
47 • Finnish
48 • Icelandic
49 • Indonesian
50 • Hebrew
51 • Lao
52 • Latvian
53 • Lithuanian
54 • Malaysian
55 • Portuguese
56 • Sri Lanka
57 • Thai
58 • Turkish
59 • Yugoslavian
60 • Danish
61 • African
62 • Amharic
63 • Arabic
64 • Croatian
65 • Somali
66 • Tigrinya
67 • Hmong
68 • Bosnian
69 • Creole
70 • Serbian
71 • Ukranian
72 • Bhutanese
73 • Chamorro
74 • Ilocano
75 • Karenni
76 • Malayo
77 • Mien
78 • Swahili
79 • Tokelauan
80 • Kannada
81 • Marathi
Prefix p p=Mr
Pronoun pro pro=1 1 • She/Her/Hers
2 • He/Him/His
3 • They/Them/Theirs
4 • Xe/Xem/Xyrs
5 • (F)ae/(F)aer/(F)aers
6 • E/Em/Eirs
7 • Ey/Em/Eirs
8 • Per/Per/Pers
9 • Sie/Sie/Hirs
10 • Tey/Ter/Ters
11 • Ve/Ver/Vers
12 • Ve/Ver/Vis
13 • Ze/Hir/Hirs
14 • Zie/Zim/Zis
Race race race=1 1 • Asian
2 • Black or African American
3 • Caucasian or White
4 • Native American
5 • Native Hawaiian
6 • Other
7 • Pacific Islander
10 • Hispanic
12 • Middle Eastern
SexualOrientation sexorient sexorient=1,2,3 3 • Asexual
5 • Bisexual
6 • Demisexual
21 • Gay
9 • Heterosexual
22 • Lesbian
19 • Other
14 • Pansexual/Omnisexual
18 • Prefer not to Say
16 • Queer
SpouseName sn sn=Abigail+Adams Supported in version 7 only.
StateProvince st st=MA
Suffix s s=Esq.
TwitterHandle tw tw=the_real_adams
WorkAddressLine1 w1 w1=1600+Pennsylvania+Ave
WorkAddressLine2 w2 w2=Oval+Office
WorkCity wc wc=Washington
WorkCountry wco wco=US; wco=CA
WorkEmail we
WorkPhone wp wp=2025551234
WorkPostalCode wz wz=20500
WorkStateProvince ws ws=DC
Yes Sign Me Up For Updates ae ae=1 or ae=true
ae=0 or ae=false

There are also elements that may not be visible, but have to do with how the form submission data is entered into the database:

Name Parameter Sample Notes
Attributed Contact ID attr attr=109418764 The contribution or event signup will have the specified contact attribution (if applied to the submission of a Contribution or Event form). The contact ID should be the VANID for an Online Actions form, or the NGP ID for a version 7 form. Since a single contribution can have more than one contact attribution, you may use a comma delimited list of IDs to attribute the contribution to more than one contact, i.e. attr=109418764,109419268
Host Committee ac ac=VN96C3TBX36 The contribution or event signup will have the specified contact attribution (if applied to the submission of a Contribution or Event form). The contact ID should be the VANID for an Online Actions form, or the NGP ID for a version 7 form.
Additionally, the ac query string will prefill the Host Committee member selection on the published form (if the query string value matches that of a Host Committee member configured for the Event).
Kiosk Mode kiosk kiosk=true Using this query string parameter disables FastAction and ActionProfile integration. This is useful if the user is using a form on a tablet or laptop in a public place and do not want the submission information remembered on that device. Notably, if you configure one form to redirect to another form (what we refer to as secondary ask), the form fields on the second fom will not be pre-populated by the submission info from the first form. If you are launching the form with knowledge of who a contact is, kiosk mode does still allow you to prefill form fields using other query string values, e.g. fn=Michelle as documented above.
MarketSource ms ms=201409_fb_birthday_v1 Can be used to track different ad buys to the same form to compare ROI
Source Code sourceid sourceid=57 Either adds or overrides the defined source code on the form. You must use the source code ID, not the source code name.
QuickSign quick quick=true Automatically submits the form and segues to the next action (thanks page, secondary ask, or an arbitrary other URL) if all the required fields are prefilled by either a query string value or ActionProfiles. This does not work for contribution or event forms.
Social Network Referral snw snw=1 Facebook
snw=2 Twitter
Indicates whether the user was referred to the form from Facebook or Twitter.

Query Strings For Specific Forms & Features

Elements that are specific to Event Host Forms (these fields are visible on the ActionTag form):

Event Information Fields

Name Parameter Sample Notes
Event Name event_name event_name=January Meetup
Event Type event_type event_type=285730 (same as Event List page filter)
Event Date date_start date_start=10-29-2018
(same as Event List page filter)
Event Start Time event_time_start event_time_start=10:30 PM
Event End Time event_time_end event_time_end=10:30 PM
Event Time Zone event_time_zone event_time_zone=America/Denver use the option value in the dropdown (inspect the dropdown in your browser)
ex: “America/Denver” and not “(UTC-07:00) Mountain Time (US & Canada)”)
Event Description event_description event_description=Let's start off the new year with an ice breaker. Bring a friend and join us at the library. Kids welcome!
Display on Event List page (Y/N) event_display event_display=1 True
event_display=0 False
Allows people to discover this event on website
Reason why not event_display_reason event_display_reason=I'm only inviting my friends Explanation why the host does not want people to discover event on website (valid only if event is not displayed)

Event Location Fields

Name Parameter Sample Notes
Location Name location_name location_name=Quincy College Anselmo Library
Street Address location_add1 location_add1=1250 Hancock St
Address Line 2 location_add2 location_add2=Ste 202
City location_ci location_ci=Boston
State/Province location_st location_st=MA
Postal Code location_pc location_pc=02144
Elements that are specific to Events List Forms (these fields are visible on the ActionTag form):
Name Parameter Sample Notes
Display Results results results=true
Distance in Miles radius radius=50
Date From date_start date_start=06-26-2018
Date To date_end date_end=06-26-2018
Event Type event_type event_type=285730,294375
Sort sort sort=2 1 • Date
2 • Distance
Elements that are specific to Events Signup Forms (these fields are visible on the ActionTag form):
Name Parameter Sample Notes
Location location location=1816
Role role role=250634
Shifts shifts shifts=11631||11632
Elements that are specific to Contribution forms with Tribute & Gift Memberships functionality enabled (these fields are visible on the ActionTag form):
Name Parameter Sample Notes
Enable Tribute Gift t t=true
Honoree Name honoree honoree=Barack+Obama
In Honor or in Memory of ttype ttype=1 “In memory of”
ttype=2 “In honor of”
Notification Send Copy recipient_em_copy recipient_em_copy=1 or recipient_em_copy=true
recipient_em_copy=0 or recipient_em_copy=false
Affects checkbox used to indicate whether or not to send a copy of a notification to the donor.
Include Recipient (Gift Memberships) tn tn=true Used for Gift Memberships. Displays contact details for recipient.
Notify Recipient (Tribute Gifts) tn tn=true Used for Tribute Gifts. Displays all recipient details.
Recipient Information
Recipient FirstName recipient_fn recipient_fn=John
Recipient LastName recipient_ln recipient_ln=Adams
Recipient Address Line 1 recipient_add1 recipient_add1=1250+Hancock+St.
Recipient City recipient_ci recipient_ci=Boston
Recipient State Province recipient_st recipient_st=MA
Recipient Postal Code recipient_pc recipient_pc=02144
Recipient Country recipient_c recipient_c=US; recipient_c=CA
Recipient Email Address recipient_em
Elements that are specific to Premiums functionality enabled:
Name Parameter Sample
Shipping FirstName shipping_fn shipping_fn=John
Shipping LastName shipping_ln shipping_ln=Adams
Shipping Address Line 1 shipping_add1 shipping_add1=1250+Hancock+St.
Shipping City shipping_ci shipping_ci=Boston
Shipping State Province shipping_st shipping_st=MA
Shipping Postal Code shipping_pc shipping_pc=02144
Shipping Country shipping_c shipping_c=US; shipping_c=CA
Elements that are specific to Story Collection forms:
Name Parameter Sample
Story Title story_title story_title=Fresh Prince of Bel Air
Story Text story_text story_text=Now this is the story all about how my life got flipped, turned upside down

Using Google Remarketing Codes

In order to use Google remarketing codes, you have to call them to load AFTER the form has loaded.

Here’s an example of what Google will give you as a remarketing code:

<!-- Remarketing tags may not be associated with personally identifiable information or placed on pages related to sensitive categories. For instructions on adding this tag and more information on the above requirements, read the setup guide: -->
<script type = "text/javascript">
    /*  <![CDATA[ */
    var google_conversion_id = 985021774; <!-- this will vary by client -->
var google_conversion_label = "lXkMCIq98gYQzvrY1QM"; <!-- this will vary by client -->
var google_custom_params = window.google_tag_params;
var google_remarketing_only = true;
/* ]]> */
<script type="text/javascript" src="">
  <div style="display:inline;">
    <img height="1" width="1" style="border-style:none;" alt=""
      src="" />

Notice that the conversion ID and conversion labels are in two places. First in the regular javascript and second inside the <noscript> code block. These are the values you need to copy into the new code snippet.

Here’s the new code you need to use, make sure to grab the conversion ID and label from the code Google provided, and insert them below. Once you’ve updated this snippet with your account information, you can copy it and paste it into the source of the form by clicking the “source” button and paste.

<script type="text/javascript">
    var img = document.createElement("img");
    var trackUrl = ""; <!-- change ID (985021774) and label (lXkMCIq98gYQzvrY1QM) in this line -->
    img.src = trackUrl;
    <div style="display:inline;">
        <img height="1" width="1" style="border-style:none;" alt=""
          src="" />
        <!-- change ID (985021774) and label (lXkMCIq98gYQzvrY1QM) in this line -->

Notes for website builder products

Using ActionTag with a website builder product like Squarespace or Wix comes with a few challenges. While we can’t support other applications, here are a few pointers we’ve learned over the years from various clients’ experiences:

  • Squarespace will not consistently render ActionTag forms if using Ajax page load. We’ve been told you can turn this setting off by going to /config/design/styles inside the settings for your Squarespace site.
  • Wix can take the embed code using their html iframe widget, but please note, this will end up iframing the form into your site, and may cause scrollbars, plus your ability to redirect to an external URL will be limited.


Data attributes on the ActionTag div are the way to pass certain data or instructions to ActionTag to influence its behavior.

Since these attributes are part of the div, any CMS or website system can easily write code that will consume ActionTag with the characteristics they desire. This is the way we have written our own Drupal modules in-house.

What follows are the data attributes we currently support:

data-form-url (required)

It is used to specify the url from which the form definition is retrieved. Only required if data-id is not used, or if presenting an advocacy related form, which requires getting the form definition from a different endpoint. Example, to load a form from a url:

<div class="ngp-form" data-form-url=""></div>

For advocacy related forms, you have to request the form definition through our advocacy service, which we creatively call advocator. This url is constructed using the following pattern:

  • Advocacy form proxy url, e.g.
  • The URL encoded database API endpoint, meaning take the endpoint and represent it like this:
  • the form ID, e.g. ntieGYzrK0meNMqRibRbAw2
  • and finally the string ngpForm at the end

Complete example for an advocacy related form, where we grab the form definition from the advocacy endpoint, with the rest of the form ID URL encoded after:

<div class="ngp-form" data-form-url=""></div>

data-id (required for legacy implementations)

It is used to specify the id of the form to render. Only required if data-form-url is not used. Please note: that some form IDs start with a minus sign (-), as shown in the example above. Do not delete this as it is a part of the form ID. Note that an advocacy-related form must use the data-form-url attribute instead. Example, to load a non-advocacy-related form with id 12345:

<div class="ngp-form" data-id="12345"></div>


(optional) - Used to specify whether to use ActionProfiles to fill the form fields. In order for this functionality to work, please contact support if you are interested in getting your URL(s) added to the allowed domains list.

Note: databag is the legacy name for ActionProfile, hence the attribute/name mismatch.

  • Default: nobody
  • Options:
    • nobody - disable this functionality
    • everybody - Allow pre-filling of information from any site in the ActionProfile network. Also requires sharing pre-fill data with other sites in the network.

Example, to enable the ActionProfile filling (assuming the site on which this tag is sitting has been allowed):

 <div class="ngp-form" data-id="12345" data-databag="everybody"></div>


(optional)- Used in conjunction with data-id to specify a non-default API endpoint for retrieving the form definition and submitting the resulting data. This is used mostly for hitting development servers; though, if you are using data-form-url you do not need this. If you are using data-id, and your database instance is accessed by a URL other than, that is you likely need to use this attribute.

  • Default:

Example, to load the definition and submit to http://developerboxname.local

<div class="ngp-form" data-id="12345" data-endpoint="http://developerboxname.local"></div>


(optional) - This attribute defines a different read endpoint from the POST endpoint defined above. This can be useful when you don’t need to personalize the form definition on a per-supporter basis and anticipate an extremely high load scenario. One could call an external cached version of the response, either from a CDN, or even flat file store like Amazon S3.

  • Default: value of data-endpoint attribute.

Example, to read the form definition from Amazon S3 instead of the NGP API servers:

<div class="ngp-form" data-id="12345" data-formdef-endpoint=""></div>


(optional)- Only available for signup forms. Used to specify the placement of the labels when the form is rendered. In general, this is discouraged, but it is available for minimal presentations for quick email signup forms.

  • Default: above
  • Options:
    • inline - sets the labels as the HTML5 placeholder attribute on the input.
    • above - displays form labels above the form fields with a

Note, the rationale here is that, while labels being above or beside the input can be altered with CSS, making them appear as placeholders is more complicated.

Example, to have labels appear as placeholders:

<div class="ngp-form" data-id="12345" data-labels="inline"></div>


(optional)- Used to specify whether the form should scroll to the form content on page load. Forms hosted by Online Actions have this parameter set to true. If you embed the form without this attribute, those will load as if you had specified it to be false.

  • Default: false
  • Options:
    • true - after the form loads on mobile devices, the form will scroll such that the form content is within the viewport.
    • false - no scroll will happen on form load.


<div class="ngp-form" data-id="12345" data-mobile-autofocus="true"></div>


(optional) - Used to specify location of ActionTag resources such as actiontag.min.css. Primarily used for internal development purposes.

  • Default:

Example, to use /sites/xyz/libraries/actiontag:

<div class="ngp-form" data-id="12345" data-resource-path="/sites/xyz/libraries/actiontag"></div>


Overview & Intended Audience

Callbacks are a rather technical feature set, and are not needed for the vast majority of uses of ActionTag. The callbacks described below are powerful, but also probably require some experience doing web development, and are not needed for most uses of ActionTag. Feel free to skip the rest of these docs unless you are a developer.

We have a series of callbacks in ActionTag which allow developers to alter bits of functionality. In order for ActionTag to know about your callback, we have a simple registration process.

First create the global JavaScript variable nvtag_callbacks (but only if it doesn’t already exist). The following snippet accomplishes this:

var nvtag_callbacks = nvtag_callbacks || {};

If your code is within a closure, you will need to explicitly ensure it is declared in the global namespace so ActionTag can find and reference it. Here that’s done with a local reference so that we no longer have to reference it by calling window.nvtag_callbacks:

window.nvtag_callbacks = window.nvtag_callbacks || {};
var nvtag_callbacks = window.nvtag_callbacks;

The last bit is callback specific. Perhaps you want to add a postRender callback to do something after the ActionTag form has been rendered.

  1. Instantiate that callback as an array if it doesn’t yet exist
  2. Create the actual callback function. The arguments to your function are the callback arguments listed below
    • Note, the first argument to a callback is always the name of that callback. This is done in an attempt to allow one function to be registered from multiple callbacks and then allow that function to handle things internally.
  3. Push your callback onto the postRender callback array

    nvtag_callbacks.postRender = nvtag_callbacks.postRender || [];
    // This function can be called anything, we don't care
    var sampleCallback = function() {
     alert("The form has been rendered!");

    Now your callback code will be called by the ActionTag at the time that postRender should happen! (which is after rendering of the form is complete).

Putting it all together:

var sampleCallback = function() {
  alert("The form has been rendered!");
var nvtag_callbacks = nvtag_callbacks || {};
nvtag_callbacks.postRender = nvtag_callbacks.postRender || [];

At the right time in the ActionTag process, we will iterate over each of the callbacks in that array and call them.

Technical background

We use our callbacks syntax to put it into the global namespace because ActionTag loads asynchronously. Also, we wish to support multiple callback sources, hence the instructions to not redeclare it over and over again.

Since our callbacks allow you to alter internals of our system, it is possible to make quite a mess of things, sometimes even in potentially dangerous/breaking ways. With great power comes great responsibility. For example, using the alterFormDefinition() callback:

var alterFormDefinition = function(args) {
  // This will blank out the form_elements array thereby effectively
  // breaking this form definition!
  args.form_definition.form_elements = [];
  return args;

So always test your callbacks carefully on a page before putting them live.

For the examples given below with each callback we are omitting the following bit:

var nvtag_callbacks = nvtag_callbacks || {};
nvtag_callbacks.postRender = nvtag_callbacks.postRender || [];

Note that this must happen for each callback in order for them to be registered and called by ActionTag.


alterErrors (args)

args is a dictionary with the following keys:

  • val - The current value of this field
  • field_name - The name of this field
  • require_valid - Errors, if any.
  • def - This element’s definition.

This callback is called when checking the error state of a field. It allows you to intercept the error and alter it.

An error should take one of the 2 following states:

  • false - There is no error
  • string - Text description of error

alterErrors example



args is a dictionary with the following keys:

  • fill_dict - The fill dictionary. Key/value pairs.
  • fill_source - None, BrowserDatabag, PreviousFormState, RecipientDatabag, or QueryString.

This callback is called after the form has completed rendering but before it is filled allowing you to intercept and alter the values which are pre-filled on the form.

Note: In order for this callback to work properly, you must return the args dictionary with your modified form_definition.



args is a dictionary with the following keys:

  • form_definition - The form’s definition, which we define as the JSON blob that composes what the form should look like.

This callback is called anytime the application requests the form definition. This is used throughout the system, both for rendering and for many other mechanics.

Note: In order for this callback to work properly, you must return the args dictionary with your modified form_definition.

Example usage



args is a dictionary with the following keys:

  • data - The form state / user data.
  • url - The URL to which the data will be posted.
  • form_id - The public ID of the form.
  • form_definition - The form definition.

This callback is called before POSTing data. It is used to alter the data that will be POSTed.

Note that only fields which already exist on the form may be modified during alterPost. It is not possible to add new fields to the form submission in this callback.



args is a dictionary with the following keys:

  • val - The current value of this field
  • field_name - The name of this field
  • require_valid - boolean, true if required, false if not.
  • form_def - The form definition.

This callback is called when determining if a field is required for the form to validate.



This callback is called when a form is submitted.

args is an empty dictionary.



args is a dictionary with the following keys:

  • view - The ActionTag form view
  • fill_dict - The fill dictionary. Key/value pairs.
  • submit - The function responsible for submitting the form.

This callback is called after the form is filled.



args is a dictionary with the following keys:

  • new_payment_method - The payment method selected on the form

This callback is called after a payment method has been chosen. No return value is expected.



args is a dictionary with the following keys:

  • form_definition: The form definition.
  • options: The view’s options.
  • thank: boolean, true if this is a thank you message, false if it is not.

This callback is called after the form has completed rendering but before it is filled. Common use cases are to fire JavaScript behaviors that require the form to be present.

var myPostRender = function(args) {
  alert("The form has now been rendered!");
  return args;

Note, multiple things induce the rendering of a form so this will likely be called multiple times. Ensure any code that depends on postRender() is tolerant of that.

Optionally receive the view and alter any options or override any methods on it:

var myPostRender = function(args) {
    return args;



This hook is called after a successful form submission, but prior to the segue to the next thing.

As a quick primer, there are, at current, 3 different things which can happen after a successful form submission:

  • Display a thank you message
  • Display another form (aka Secondary ask)
  • Redirect to another page anywhere on the internet

preSegue() happens before the transition to this next step so it’s useful for intercepting it and altering the behavior based on the submitted values and/or the response from the server.

It receives two arguments:

  • submitted_values - The values which were submitted across the network
  • response - The response from the server to that submission



This hook is called when a segue is happening.

As a quick primer, there are, at current, 3 different things which can happen after a successful form submission:

  • Display a thank you message
  • Display another form (aka Secondary ask)
  • Redirect to another page anywhere on the internet

We call the transition from one thing to another thing a segue. This callback is called when making that transition.

Note, it is NOT called in case 3 above because we have no control over another page on the internet.

It receives three arguments:

  • formviews - The form views in question
  • thank - boolean, true if this is a thank you message, false if it is not.
  • calling_tag - The view in question.

Third Party Integrations

Google Tag Manager Event Tracking

ActionTag integrates with Google Tag Manager Event tracking so that you can more readily understand how users are interacting with your forms. This integration is available on all form types. It is reccomended that you utilize Universal Analytics in your Google Tag Manager implementation.

Google Analytics Events

This is the data that will be passed to Google Analytics via Google Tag Manager upon successful integration. This data will be viewable in the Google Analytics Events reporting interface.

Event Trigger eventCategory eventAction eventLabel eventValue
Form loaded postRender callback ActionTag form type, e.g. Contribution, Petition Form Load Form Template Number of fields in the form
Form fill postFill callback ActionTag form type, e.g. Contribution, Petition Form Fill Form fill source, identical to the value of fill_source during alterFill, e.g. FastAction Number of fields filled
Form submitted preSegue callback ActionTag form type, e.g. Contribution, Petition Form Submit Submit Button text, e.g. Contribute, Donate For ActionTag forms of type Contribution or Event, the monetary amount paid
Form abandoned window.onbeforeunload event ActionTag form type, e.g. Contribution, Petition Form Abandoned Last field focused on (using the name assigned to the input element), e.g. SelectAmount, FirstName Number of fields completed
Captcha called form submission (except Smart Links) ActionTag form type, e.g. Contribution, Petition Captcha Called Google Recaptcha v2 Invisible (null)
Additional dataLayer Variables

In addition to eventCategory, eventAction, eventLabel, and eventValue, the following variables are sent to the Google Tag Manager dataLayer when each event fires.

Field Value
sourceCodeId The source code that will be applied to the person who submits this form - retrieved from the query string parameter if present, or from the form definition if not present in the query string
activistCodes An array of activist code IDs that will be applied to the person who submits the form
tenantUri A unique string relating to the committee that the form is associated with
formName The form name selected during the creation process
formShortCode A unique identifier that can be utilized to search for the form inside Online Actions

The following object provides an example of data that would be passed into the Google Tag Manager DataLayer when a Contribution form is loaded.

    event: 'FormEvent',
    eventCategory: 'ContributionForm',
    eventAction: 'Form Load',
    eventLabel: 'Minimal',
    eventValue: 12,
    activistCodes: ['3456','8901'],
    sourceCodeId: 2345,
    tenantUri: 'ngpvan://van/EA/EA001/1/2',
    formShortCode: 'OQbID4vGGESISlTSrmpTsw2'
Utilizing Form Events in your Google Tag Manager Setup

Before completing these steps, ensure that your Google Tag Manager container is installed properly and utilizing the default “dataLayer” on the page which displays the ActionTag form.

  1. In your Google Tag Manager container, create a new Trigger with the trigger type “Custom Event”.
  2. Set the Event name for your new trigger to “FormEvent” (this is case sensitive) and allow the trigger to fire on All Custom Events.
  3. Create four new User-Defined Variables with the Variable type “Data Layer Variable”, with the following Data Layer Variable Names: “eventCategory”, “eventAction”, “eventLabel”, and “eventValue”.
  4. Create a new Universal Analytics Tag.
  5. Set your Tracking ID in your Universal Analytics Tag to the Google Analytics property of your choice.
  6. In your Universal Analytics Tag, select Track Type “Event”
  7. For each Event Tracking Parameter, using the macro selection, input each of the User-Defined Variables that were created in Step 3 to their appropriate slot.
  8. The Tag should have Non-Interaction Hit set to “True”, so that pageviews for ActionTag form interactions are not recorded in duplicate.
  9. Set the trigger for the Universal Analytics tag to the one created in Step 1.
  10. Use the preview setting in the Google Tag Manager container to look at one of your forms to debug and confirm the integration is enabled successfully. Do this by submitting a form and watching (in the Google Tag Manager debugger) for your new Form Events tag to fire successfully.
  11. Via the Data Layer tab in the debugger, inspect the data layer to make sure that the correct information has been passed.
  12. Verify that your data appears in the Google Analytics Events section. Note that it may take up to 24 hours for your data to appear.
  13. Publish the container and ensure that it appears on all pages where ActionTag is present.

Enhanced Ecommerce tracking in Google Tag Manager

Google Tag Manager (GTM) exists to help you load your Google Analytics (GA) and any other arbitrary JavaScript or HTML tags in the same “container”.

Google Analytics also has an Ecommerce reporting feature, designed to mimic a system where items are added to a cart and then the cart is checked out. We have configured ActionTag to fire Ecommerce events on successful contribution and event form submissions. In the case of a contribution form submission, only a single item will appear in the cart for a transaction. In the case of an event ticket purchase, multiple items can will in the transaction if different ticket types are purchased by the supporter.

If you are using Google Tag Manager with Google Analytics on the same site where you embed ActionTag, and you enable Google Analytics Ecommerce collection in both Google Analytics and Google Tag Manager, the Ecommerce data should pass to the appropriate Google Analytics Ecommerce reports with the following configuration steps.

  1. Ensure that Google Tag Manager is installed on your online form, as follows:
    1. In Online Actions: Provide your Google Account ID Number on Step 1 of the Form Builder.
    2. In NGP: Embed the Google Tag Manager source in the body on your form.
    3. If you are embedding ActionTag on your site, you can install a new GTM container on your site or utilize an existing GTM container.
  2. In Google Analytics, navigate to the property that will be utilized for tracking enhanced Ecommerce. For each view that requires Ecommerce, navigate to the view settings, ‘Ecommerce Settings’, and Enable Ecommerce. Ensure that Enhanced Ecommerce Reporting has been enabled as well.
  3. In Google Tag Manager, create a Custom Event trigger type that is set to fire on all custom events with the event name: transaction.
  4. Now create a Universal Analytics tag in Google Tag Manager with type “Page View”. Typically Google Tag Manager is used to house a Google Analytics tag to track page views. You can track your Ecommerce data to this same web property. Set the Tracking ID to the same property that tracks pageviews.
  5. While configuring the tag, click “More Settings” and expand “Fields to Set.” In the “Field Name” section enter in “nonInteraction” (case sensitive), and in “Value” enter in “true.” This step ensures that pageviews are not double-counted when form events fire.
  6. Also under “More settings”, expand “Ecommerce” and click the checkbox for “Enable Enhanced Ecommerce Features” as well as the “Use data layer” checkbox.
  7. Once your tag has been configured, trigger the tag using the transaction Event trigger created earlier.
  8. Use the preview setting in the GTM container to look at one of your forms to debug and confirm the integration is enabled successfully. Do this by submitting a form and watching (in the Google Tag Manager debugger) for the Ecommerce tag to fire successfully.
  9. Via the Data Layer tab in the debugger, inspect the data layer to make sure that the correct information has been passed.
  10. Verify that your data appears in the Google Analytics Ecommerce section. Note that it may take up to 24 hours for your data to appear.
  11. Publish the container and ensure that it appears on all pages where ActionTag is present.

Google Tag Manager utilizes a DataLayer in which information is stored in a JavaScript array and sent to the GTM container. The following code snippet is an example of data that would be passed into the GTM DataLayer upon a successful contribution form submission.

dataLayer = [{

  /* Triggering Event */
  'event': 'transaction',

  'ecommerce': {
    'purchase': {
      'actionField': {
        /* Online Ref # (can be used to search for transaction) */
        'id': '25970195',

        /* Denoting a Transaction from ActionTag */
        'affiliation': 'NGPVAN',

        /* Total Transaction Revenue */
        'revenue': '2600.00'

      'products': [
         * ID based upon unique session ID, combined with the
         * individual product transaction.
         * This value does not remain staticly assigned to the item for 
         * future purchases or for purchases by other users;
         * it is unique to the session)
          'id': 'People for Good_4_713_2600.00',

          /* Unit Price (Contribution Amount) */
          'price': '2600.00',

          /* Organization Name */
          'brand': 'People for Good',

          /* Form Type */
          'category': 'ContributionForm',

          /* Count of Items */
          'quantity': 1,

          /* Selected Product */
          'name': 'People for Good_4_713_2600.00'

The following code snippet is an example of data that would be passed into the GTM DataLayer upon successful client-side form submission, for an event with multiple tickets.

dataLayer = [{

  /* Triggering Event */
  'event': 'transaction',

  'ecommerce': {
    'purchase': {
      'actionField': {
        /* Online Ref # (can be used to search for transaction) */
        'id': '25970195',

        /* Denoting a Transaction from ActionTag */
        'affiliation': 'NGPVAN',

        /* Total Transaction Revenue */
        'revenue': '200.00'

      'products': [
         * ID based upon unique session ID, combined with the
         * individual product transaction.
         * This value does not remain staticly assigned to the item for 
         * future purchases or for purchases by other users;
         * it is unique to the session)
          'id': 'People for Good_4_713_40.00',

          /* Unit Price  */
          'price': '40.00',

          /* Organization Name as it Appears */
          'brand': 'People for Good',

          /* Form Type */
          'category': 'EventForm',

          /* Number of Tickets of this Type Purchased */
          'quantity': 1,

          /* Selected Value or Ticket Name */
          'name': 'Gala Silver Ticket'
            'id': 'People for Good_4_713_80.00',

            /* Unit Price */
            'price': '80.00',

            /* Organization Name as it Appears */
            'brand': 'People for Good',

            /* Form Type */
            'category': 'EventForm',

            /* Number of Tickets of this Type Purchased */
            'quantity': 2,

            /* Selected Value or Ticket Name */
            'name': 'Gala Gold Ticket'

For more information on Google Tag Manager usage:

Google Tag Manager Quick Start Guide

Learn more about the Datalayer from Google

Google Analytics Ecommerce Tag Information


Restyle credit card field

Apply custom styling to the credit card iframe fields


var nvtag_callbacks = window.nvtag_callbacks = window.nvtag_callbacks || {};
nvtag_callbacks.alterFormDefinition= nvtag_callbacks.alterFormDefinition|| [];
nvtag_callbacks.alterFormDefinition.push(function (args) {
  if(args && args.form_definition && args.form_definition.form_elements) {
    var paymentInfo;
    for(var i = 0; i < args.form_definition.form_elements.length; i++){
      var topLevel = args.form_definition.form_elements[i];
      if(topLevel && === 'PaymentInformation'){
        paymentInfo = topLevel;
    if(paymentInfo && paymentInfo.children){
      var account, cvv, exp;
      for(var j = 0; j < paymentInfo.children.length; j++){
        var child = paymentInfo.children[j];
        if(child && === 'Account'){
          account = child;
        } else if(child && === 'SecurityCode'){
          cvv = child;
        } else if(child && === 'ExpirationMonth') {
          exp = child;

        console.log('updating Account styling');
        account.styles = { color: 'red' }; // add style overrides
        console.log('updating SecurityCode styling');
        cvv.styles = { color: 'green' }; // add style overrides
        console.log('updating Expiration Date styling');
        exp.styles = { color: 'yellow' }; // add style overrides
console.log('alterFormDef', args);
return args;


Take the provided error message and adjust it to something else.


var myAlterErrors = function(args) {
      if (args.field_name === 'FirstName') {
        if (args.errors) {
          args.errors = ["YOU MUST GIVE US YOUR FIRST NAME TO PROCEED"];
        } else {
          if (args.val !== "Frank") {
            args.errors = ["We only accept a first name of Frank"];
      return args;

var nvtag_callbacks = nvtag_callbacks || {};
nvtag_callbacks.alterErrors = nvtag_callbacks.alterErrors || [];



A simple use case is to override some attribute of the definition:

// Implementation of an alterFormDefinition Callback
var alterFormTitle = function(args) {
  // Note, changing this title will not make a visual change unless the title is
  // used in the template which it's not by default in ActionTag.
  args.form_definition.title = "This title has been overridden";
  $('.status').html("<pre>Form Title: " + args.form_definition.title + "</pre>");

  // Must return the altered object so it will be used
  return args;


A bit more complex example is to alter something within the form definition. Let’s say you want to change the contents of the Header HTML markup. Note, in this example we are using the Underscore module to iterate over the elements

var changeHeaderHtml = function(args) {
  // args is a dictionary with a key of "form_definition"

  // iterate over each element, 
  _.each(args.form_definition.form_elements, function(child, index) {
      if ( === 'HeaderHtml') {
          child.markup = "<p>Replaced Markup</p>";

  return args;

Advanced: adding a field

Let’s say you want to add a field to the form definition to be collected:

var addSpouseField = function(args) {
  _.each(args.form_definition.form_elements, function(child) {
      if ( === 'ContactInformation') {
          spouse_field = {
              name: 'Spouse',
              title: "What is your spouse's name?",
              type: 'textfield',
              weight: 99, // We want it to appear at the bottom of the fieldset
              queryString: 'sp'
  return args;

Note, for this case, if Spouse is not in the original form definition, the API would not be able to parse it, so you will need to intercept and store that POST value somewhere else.

Also note that since the added definition has a queryString of 'sp', it will fill if the page has a query string argument like: ?sp=Joe

Rearrange fields

Let’s say we want to rearrange some fields. Or perhaps we want to move some fields into another fieldset. The following example covers that case:

var rearrangeFields = function(args) {
  // First add a new fieldset to hold these fields
  var name_fieldset = {
      name: 'Name',
      title: 'Name',
      type: 'fieldset',
      children: []
  var name_index = args.form_definition.form_elements.push(name_fieldset);
  // Decrement as push returns the length, we want reference to the last element

  _.each(args.form_definition.form_elements, function(child) {
    if ( === 'ContactInformation') {
        _.each(child.children, function(element, key, children) {
            if ( === 'FirstName' || === 'LastName') {
                // Add to our new name fieldset

                // Remove from the other fieldset
                children[key] = { 'type': 'hidden'};
        child.title = 'Address';
  return args;

In this case we are creating a new fieldset for Name, moving the name fields into that fieldset, removing them from their original fieldset (ContactInformation), and changing the title of the Contact Information fieldset to Address to better indicate its purpose.

Redirect based on recurring or contribution amount values

Perhaps you want to change where a donor goes after form submission in case they choose to give over a certain threshold or choose to give a recurring contributon. Using the preSegue callback you can look at the submitted values and make conditional redirects based on that information. Note, in practice you probably only want to use one of these two conditionals, but both are shown in the same example below for expediency:

var nvtag_callbacks = nvtag_callbacks || {};
nvtag_callbacks.preSegue = nvtag_callbacks.preSegue || [];
nvtag_callbacks.preSegue.push(function submitSegue(args) {
  var contribAmount = parseFloat(args.postVals.Amount);
  var isRecurring = args.postVals.IsRecurring;
  if (isRecurring) {
      window.location = "";
  if (contribAmount > 5000) {
      window.location = "";
  return args;

Obviously, you will want to adjust the threshold for high (or low) dollar conditional redirects, as well as the redirection destination in the above examples.


Perhaps you want to track the contribution amount in another analytics package. Here’s how you capture it on form submission:

var contribAmount;
var submitSegue = function (args) {
    contribAmount = args.postVals.Amount;
    return args;
var nvtag_callbacks = nvtag_callbacks || {};
nvtag_callbacks.preSegue = nvtag_callbacks.preSegue || [];

You could then call the variable contribAmount to pass off to your analytics service.

Alter country list

If you want to alter the list of countries on your forms, the following example shows you how to remove a country, rename a country, or potentially insert a new option, all using the postRender callback. Note: if adding a new country, make sure you map it back to an existing value so the address is entered to the system in a way we can process

var alterCountries = function(args) {
  // Remove a country by the value in the dropdown
   var removalItem = document.querySelector('select[name=Country] option[value="XK"]');

  // Rename a country publicly (but will map to the existing value in the database)
  var renamedItem = document.querySelector('select[name=Country] option[value="VI"]');
  // desired new text to display
  renamedItem.innerText = 'US Virgin Islands';

  // Insert a new country (not recommended, only use it to map a new entry to an existing value)
  // replace "Dominican Republic" with the name of country that comes right before the country you wish to add
  var previousCountry = document.querySelector('select[name=Country] option[value="EE"]'); 
  previousCountry.insertAdjacentHTML('afterend','<option value="Essos">Essos</option>');
var nvtag_callbacks = nvtag_callbacks || {};
nvtag_callbacks.postRender = nvtag_callbacks.postRender || [];