Frequently Asked Questions

Many of these topics are covered elsewhere in this guide in which case we've provided a link to the relevant section. More code snippets are available in Developer Examples and Tutorials.


How can we improve our deliverability?

Our most comprehensive guide on email deliverability and inbox placement is available in this training video:

While the above video is generally good advice, there is no definitive solution that will ensure all of your messages make it to users' inboxes and not their spam folders.

Some additional things to keep in mind include:

Always clearly indicate that signers will be subscribed to your mailing list. Every mailing must include a clear unsubscribe link. Purchased or bartered email lists may not be mailed to using ActionKit without our prior approval.

The biggest factor in determining whether a mailing gets flagged as spam is how your members interact with it. Filtering is almost all reputation-based now. The specific scoring systems that ISPs use for spam filtering are opaque. This makes sense; if spammers can learn what the filters are for a given ISP they can exploit their network. Broadly we know that higher open and click ratios help. Lower percentages of users bouncing or reporting you as spam help.

You can improve your rates and remove spam traps from your list by unsubscribing users who have not engaged with your mail stream for a long time. We've added tools to help you implement a list hygiene and re-engagement program.

We help manage your reputation, signing you up for feedback loops and allowlisting programs where possible. If you're getting reports of emails that are going to users' spam folders, report that to us through the support webform and attach the email so we can see the header. Sometimes we'll see something that you can change. Sometimes there's no clear reason and we'll follow up with the ISP. We can't take that step, however, until you've established some mailing history through ActionKit so we can get bounce rate/spam complaint numbers to the ISP.

Note that although we automatically sign you up for feedback loops (which are used to automatically unsubscribe users who mark your mailings as spam), Gmail does not have a participating feedback loop program. Because of this, if a Gmail user clicks "Report spam", Gmail will not report who clicked spam or how many users clicked Report spam.

You can see spam click rates by signing up for Google Postmaster, but this information isn't currently available to us for Gmail users.

Since spam complaints from Gmail addresses are not known, that means the spam complaint stats reported in ActionKit (and in any other system) are undercounts.

You can also test your emails to see if certain changes make a significant difference in your rates. Keyword filtering is mostly a thing of the past. But, if more users don't open your message or mark it as spam with particular wording, that may affect filter behavior. A long subject line will get truncated at an arbitrary length by most mail clients. That may have the same effect.

You can review current guidelines to learn about specific triggers and to get a sense of what hurts versus helps. But remember that these change regularly as spammers try new approaches and ISPs update their filters to catch them.

Gmail has some information about their rules here:

I'm getting reports from users of delayed delivery to a domain.

Mailbox providers will sometimes throttle or block messages for a period, which is easy to track by looking at the Bounce/Delay Metrics screen. We will automatically retry delivery when delayed to ensure your message eventually gets delivered. Some delays can be expected from time to time, which can depend on your sender reputation with a given mailbox provider, your sending volume, and your sending speed. Complicating matters further, some mailbox providers are more strict than others.

When you have delays at a mailbox provider, this is often an early warning sign that your sending volume is too high or too fast for your sender reputation. Using rate limiting is typically the best option -- for more details including how much to rate limit with our Max emails/second feature and how to avoid common mistakes when rate limiting, see our blog post Keep an Eye on Deliverability.

Beyond using rate limiting, the section on deliverability has our best information on how you can work to improve your sender reputation and inbox placement, which helps to minimize delays.

Is ActionKit Email DKIM Identified and SPF Signed? Should I Set Up DMARC?

We think setting up DMARC is a great idea for all clients and encourage it. As of February 2024, DMARC is essentially a requirement due to Gmail/Yahoo's new rules.

Your ActionKit email is "domain aligned" -- that is, your envelope from ( and your friendly from ( -- are in the same domain. All of your mail is SPF identified and DKIM signed. So your ActionKit email is ready for DMARC.

However, before you can start enforcing a DMARC policy of quarantine or reject, you'll need to make sure that all the rest of the email you are sending is domain aligned, SPF identified and DKIM signed before you can start enforcing a DMARC policy of quarantine or reject.

We recommend signing up for a service like DMARCIAN (, set up a DMARC record with a policy of "none" and give yourself a few days or a week's worth of reports, so that you can identify legitimate sender sources in your universe that you will need to address before you can start enforcing a quarantine or reject policy.


Can I view the text version of an email?

Some email clients (Outlook, Thunderbird, and possibly Mac OS X Mail) have a "view as plain text" option in the menus, but the easiest way to get to plain text is in GMail: choose "Show Original" from the menu next to Reply.

How do I make a template for future emails?

You can mark a mailing as a Model to create an example mailing to be copied for future use by checking the box on the Compose Email screen. Model mailings can not be sent, but can be copied to create new drafts. You can create a model to act as a template for a particular kind of mailing, including the from line, standardized aspects of the message body, and basic targeting rules. Later, you can copy this model to create a a draft that shares those common elements, edit it as needed, and send it normally.

How do I do an A/B email test?

You can test subject lines head-to-head by entering multiple subjects when you create your mailing. Read more under subject line testing.

For any other type of head-to-head testing (e.g. design, content, from lines) you can use A/B Tests for Mailings, which can send variations of parts of a mailing and offer a comparison report where you can click to select the winner.

How does ActionKit track bounces? Do you track hard and soft bounces separately?

Hard bounces (invalid email or account does not exist) show up in the core_bounce table. Users are unsubscribed after one hard bounce.

Generally, we don't unsubscribe for transient or "soft" bounces, since they are transient. Users who emit transient bounces either eventually turn into permanent failures or resolve themselves.

Some users who have repeated soft bounces due to their mailbox being full can be unsubscribed automatically, and `we recommend setting this up. <`_

If a user is unsubscribed due to bounces, their subscription_status in the core_user table changes to "bounced" and there's an entry made in core_subscriptionhistory with change_id=3.

Can I embed survey answers in a bulk email?

Yes, using merge queries or a merge file with the user_id as the first column and survey answers as the following columns.

There's no snippet for this because the mailer doesn't have a way to know which action to lookup - even with a given page each user may have multiple actions.

How do I add a query to the query library to use for targeting emails?

You can make any query report from the Reports tab available through the Query library by adding the mailer tag to the report. Targeting queries must return the user_id as the report's first column.

What happens if I hide a mailing list?

Hiding a list removes it from dropdown select menus in the ActionKit admin interface, preventing your staff from setting it as the mailing list for pages created in the future.

Any existing pages that have been linked to that mailing list will continue to subscribe users to it. Any users that were previously subscribed to that mailing list will remain subscribed and will still see that list as a choice on unsubscribe pages.

If you want to completely disable a mailing list you'll need to unsubscribe all users from the list, reassign all pages linked to the list, and finally, hide the list.

Marking a list as hidden will not remove it from the database or get rid of any user subscription history information.

Does hiding a list hide it on the unsubscribe page for users?

No. Hidden lists will still show up on the user's subscription history and are still pre-checked on the unsubscribe page. Same goes for public unsubscribe pages.

How do I integrate litmus tracking in an ActionKit email?

In their documentation, Litmus recommends that you use a unique identifier like a subscriber email address as the merge tag in their tracking code. In ActionKit, this merge tag could be {{}}.

To begin, create a new email wrapper and give it a name. In the template box area, replace

{% block content %}{% endblock content %}

with your Litmus tracking code. Below is an example you can use.

{% block content %}{% endblock content %}
    @media print{ #_t { background-image: url('{{}}');}}
    div.OutlookMessageHeader {background-image:url('{{}}')}
    table.moz-email-headers-table {background-image:url('{{}}')}
    blockquote #_t {background-image:url('{{}}')}
    #MailContainerBody #_t {background-image:url('{{}}')}
<div id="_t"></div>
<img src="{{}}" width="1" height="1" border="0" />

Be sure to replace each of the XXXXXXs above with the unique string of characters associated with your Litmus tracking code.

How do I add preview text to a mailing?

Preview text is directly supported. See Subject and Preview Text for more information on entering it and learn how to add it to your email wrapper here.

I hit send too quickly. Can I undo that?

Once you hit Send, the mailing will start sending. If you run into this problem often, a superuser can configure a delay on your sends. With that delay, staff with "receive all mailings" permissions will receive the mailing immediately, but it won't go to your universe until the delay has passed, giving you additional time to catch mistakes.

There is no way to pull back mailings that have already sent, but if you act quickly, you could hit Stop on a mailing that has not yet finished sending to its entire universe and prevent the rest of the universe from receiving that mailing.

If you want to stop and re-send a mailing due to a broken link, you can edit the link under without stopping the mailing.

If you want to resend the mailing to the users that have not yet received the mailing (for instance, you found a typo, hit Stop, and want to resend after fixing it) then you will want to:

1: Copy the stopped mailing to create a new mailing.

2: Update the new mailing's content or targeting as applicable.

3: Add an exclusion of the stopped mailing when targeting the new mailing.

4: Hit send on the new mailing.

How do I use 4-byte emoji in mailing subject lines?

As of version 2.3.21, you can use 4 byte emoji, such as 👻 or 💩 natively in ActionKit bulk emails.

How do I add text that only displays for donors?

If you want to display some text in a mailing that’s only visible to donors, you can use ActionKit’s donation snippets with the Django {% if %} syntax to check whether a value for the snippet exists, and then use that logic to display your message.

For example:

{% if donations.highest_previous_all %}
   P.S. Thanks for being one of our most wonderful donors!
{% endif %}

This message will only show for donors.

What are merge files and how do I use them?

Merge files are CSVs or TSVs containing user-specific data that you can upload and insert into your mailings to make the mailing content more targeted.

Let’s say you’re mailing out reminder to your members about the deadline to register to vote in each state for the upcoming presidential election.

The registration deadline dates aren’t stored in ActionKit, but you can create a CSV or TSV file containing the voter registration deadline matched with each state.

Upload the CSV file by going to Mailing -> Data -> Mergefiles, and clicking on the Add Merge File button.

Then, in a mailing, we can insert a snippet such as {{merge.registration_deadline_presidential_2016 }}, and the deadline that matches the mailing recipient’s state will show up.

For example, if the user lived in California, {{merge.registration_deadline_presidential_2016}} would output October 24th, 2016.

You can send a few proofs to yourself to confirm that the content reflects the expected outputs.

There are many more uses for merge files, too — such as local events or asks for the user to call a local newspaper. Just make sure you’re matching the first column on a geographic designation or a user source (like city, state, zip, user_id or email).

Read more about merge files here:

How do I use auto excludes to order my mailings?

Auto excludes is an optional feature that you can turn on and configure in your instance. It changes how you set up and manage draft and scheduled mailings.

If you turn on auto excludes for your organization, you specify a send date on your drafts, and sort drafts into an order to determine what excludes what. Typically, you place broadly-targeted drafts (that should exclude most others) at the top of the order, more narrowly targeted drafts (excluded by the broader drafts) further down, and random-sample tests (which usually exclude nothing, to get a clean random sample) at the bottom.

To start using auto excludes, you have to turn it on for your instance in your CONFIG, which you can access if you have SuperUser level permissions.

Now create or open a draft. On the targeting screen, you’ll see a checkbox to enable auto excludes. Individual mailings can have auto excludes on or off: the ones with it enabled exclude each other as needed automatically, and the ones without it only exclude (or get excluded) by hand, via Exclude Groups -> Mailings. Even if most of your drafts use auto excludes, there might be a few urgent or otherwise special drafts where you want to to “double hit” subscribers you already mailed today; for those, you’d disable auto excludes.

Once you have two or more drafts on a given day, you’ll also have to drag and drop them into an order so ActionKit can know what should exclude what. Each draft excludes those below it. Your broadest mailings (e.g., full-list) generally need to exclude the most other drafts, so they go at the top. Narrower mailings need to exclude fewer drafts, so they go further down. If two mailings go to naturally different audiences (e.g., one goes to California and the other to New York), it doesn’t matter what order they’re in. Often, once you’ve arranged mailings into a few general bins (full-list mailing, narrow mailings, random tests), exactly how you order isn’t that important; if your targeting counts aren’t way out of whack, you’re probably OK. You can use a given draft’s targeting screen to reorder any auto-excluding drafts, not just the one currently being edited.

After you submit your draft’s targeting, its targeting summary will include a line listing exactly which drafts it excludes. You might notice it also has a line about sent mailings: draft for today will exclude all sent mailings that have auto-excludes enabled in order to prevent users from accidentally getting mailed twice.

On the mailings dashboard (/dash/mailings/), you’ll see mailings arranged by date and in the order you set up on the targeting screen (plus a section for undated drafts). Each date has a “Rebuild” link, which rebuilds drafts marked as needing it, and a “Reorder” link that lets you drag them around without going to a mailing’s targeting screen.

The auto-exclude setting does not actually schedule your mailings. You still need to schedule your mailing or just hit send, as you do now, to send your mailing. Scheduled mailings are including in the list for reordering from the targeting screen or the dashboard (although you won’t see them in the list until you hit reorder on the dash).

Note some things this feature does not do:

  • It doesn’t prevent your mailings from needing rebuilds, or automate rebuilds much. The “rebuild” link for each date on the dashboard is just equivalent to clicking “Rebuild now” on the top draft for that date. The “Reorder” link on the dashboard, or reordering from the targeting screen, does not automatically start a rebuild (it does mark which drafts need a rebuild, though).
  • It doesn’t help you when mailings “slip” from one day to the next. For each mailing that “slips”, you need to manually go to its targeting screen and submit with a new date.
  • It doesn’t help you with recurring mailings. They can’t use auto-excludes.
  • It doesn’t avoid overlap with non-auto-excluding mailings. Even if the non-auto-excluding mailing went out first, if you want to avoid overlapping it you have to use Exclude Groups -> Mailings.
  • It doesn’t use your campaigner or mailing time zone settings. It’s minor but noteworthy: only your group’s site-wide time zone setting is used to determine when each day starts for purposes of auto-excludes scheduling. (The setting is at /core/admin/todaytimezone/, also reachable by clicking “timezone setting” from the auto excludes setting page.)

Is there a way to capitalize the first letter in all user names?

The way to do this, whether or not the user first name is capitalized in core_user:

Use the capfirst filter, like so:

{{user.first_name|capfirst|default:"Member" }}

How are opens tracked for mailings? Why do some users show clicks on a mailing without an open?

ActionKit inserts a tracking pixel into your mailing, and every time the image is downloaded, we record an open. However, if the user has images turned off for their email client, which it is by default in some programs and based on your reputation in others, then we will not know if they opened the mailing.

Note that users who are enrolled in Apple's Mail Privacy Protection (MPP) will not report opens, but these machine opens are stored in the core_open_raw table.

This can lead to some odd results, like having more clicks than opens. Read about how we calculate opens and clicks in the mailing report.

Why is my mailing targeted to fewer users than I’d expected?

There are several possible explanations, including:

  • The mailing is still rebuilding.
  • The mailing excludes other mailings that are larger than you thought; possibly because those mailings may have been rebuilding too.
  • If you are using an event snippet, events only pull in future events, which may mean that some areas that you thought you were targeting are actually not within the mailing universe.
  • You could be comparing the mailing count to the results of a query report that isn’t limited to subscribed users. The mailer automatically limits to subscribers.

And just as a reminder, the categories in “Includes” are ANDed together – so if you specify both “Tags: wildlife” and “State: CA” in the Includes, then you are only targeting people who have both taken action on a page tagged “wildlife” AND live in CA.

Why am I not receiving a proof?

The first thing to check is that the mailing isn’t currently rebuilding. No proofs send until the mailing has finished building, though you can specify a user by ID or email address to avoid having to wait.

Next, check your spam folders and filters to make sure the proof didn’t get filtered out.

If you still don’t see a proof, then contact us via Support – there may be a delay at the email service provider, or if you have clicked “spam” in the past (probably accidentally), then you wouldn’t receive any mailings and we would need to clear that block with the email service provider.

How can I make sure that members won’t get the same recurring mailing twice?

We provide a built-in mailer query called "People who recently received a recurring series". Add this to your excludes criteria and provide the recurring schedule ID for the recurring mailing and the number of days that you want to avoid resending.

If you want to prevent someone who has received any recurring mailing within a timeframe from receiving another recurring mailing, even of a different type, then use 0 as the recurring mailing schedule ID.

Read more about recurring mailing targeting.

Can I reference the subscribing petition in the first welcome email for a new user?

Yes! You can pull this information in using a merge query. Just create a query with the user_id as the first column and the page title as the second column, and then use the merge snippets to pull in the page title in your mailing.

How can I target a mailing to people who didn’t donate but did click through?

For users who clicked through a mailing, but did not finish taking action on a page, you can use a built-in mailer query called "Click on Page but no Action (click_no_action)".

How are subject lines randomized?

Users get split up into the subject line test groups using this formula: user_id % n, where n is the number of subject lines. %, or the modulo operator, is a way to pseudo-randomly split a group into a set number of buckets based up on the remainder value when you divide the group by the number of buckets.

Read more about the modulo operator here:

How does caching of mailing reports work? How often does that run?

Caching of mailing queries can make it faster for you to target your mailings, especially if you have complicated queries that take a while to run but whose results do not change often and therefore do not need to be rerun for every use.

You can set the queries to refresh every hour, daily, or weekly. The report will then automatically rebuild within an hour of it expiring.

How can I make sure that we never email a certain group of people? Is there a way to set some default excludes for mailings? How do we block users? How can we block an entire domain?

You can address this a few different ways.

If there are specific email addresses or domains that you never ever want to email, then you can add them to your blackholed email and domain lists.

And you can also set up your mailings to automatically exclude certain lists by default, or to use specific mailer queries for exclusions by default. You can set those defaults by going to your CONFIG gear menu and changing the Mailer Targeting Defaults.

How do I use suggested ask amounts with ActBlue donation pages?

The suggested ask formulas are linked to ActionKit pages, so it takes an extra step or two to get them to work for ActBlue. First, you'll want to create a dummy donation page with your preferred suggested ask formula to use in the landing page field for your mailing. You'll still link to your ActBlue page in the mailing body. This should allow you to use our suggested ask functionality even though you're not using our donation page to actually collect donations.

Then you'll want to pass the amount from our suggested ask on to ActBlue. You can do that by setting the amount query parameter to {{ suggested_ask }}.

The suggested ask formula gives you exactly one number. To give more than one number there, you could use filters to multiply the suggested ask by .5, 1.5, 2, and 3 (for example) and round to the nearest integer -- decide the formula that makes sense to you. Each amount would be a combination of filters: {{ suggested_ask|multiply:'0.5'|floatformat:'0' }}. Together in an ActBlue URL, that code would look something like:;amounts={{ suggested_ask|multiply:'0.5'|floatformat:'0' }}, {{ suggested_ask }},{{ suggested_ask|multiply:'1.5'|floatformat:'0' }},{{ suggested_ask|multiply:'2'|floatformat:'0' }}

Rounding to multiples of 5 or 10 is less elegant but doable.

  • This code will round to the nearest $5 increment: {{ suggested_ask|multiply:'2.5'|multiply:'0.2'|floatformat:'0'|multiply:'5' }}
  • And this will round to the nearest $10 increment: {{ suggested_ask|multiply:'2.5'|multiply:'0.1'|floatformat:'0'|multiply:'10' }}

(The first |multiply:'2.5' in each is the factor you're multiplying the suggested ask by.)

How do I send donation receipts in the right time zone?

Order snippets in confirmation mailings and notifications are based on UTC, not your instance's time zone. There are three options that may work depending on your needs. The first two use Django date formatting to pull a time into the snippet.

  • Simply put a full time and time zone on the receipt so users can convert to their local time.
{{ order.created_at|date:"F j, Y f A" }} UTC
  • Manually override the snippet with the date_add filter. So you could use this code to convert from UTC to EST. National or international orgs may still want to add a time zone so folks in California who donate after 9 p.m. could claim the donation for that fiscal year, even if you're showing the time zone in Eastern time.
{{ order.created_at|date_add:"hours=-5"|date:"F j, Y f A" }} EST.
  • Load time zones and convert automatically. This option has the advantage of switching from Daylight Savings to Standard Time throughout the year.
{% load tz %}
    today is: {{ order.created_at|timezone:"America/New_York" }}


Is there a record of all changes to a user's list membership and subscription status?

Changes in a user's subscription status and list membership are recorded in the core_subscriptionhistory table. The change_id shows the reason for the change. Join to core_subscriptionchangetype to include the name of the change instead of the code in a query. Join to core_action using the action_id to see the related action and page_id (where there is a related action).

1: subscribe: User subscribed by taking action on a page.

2: subscribe_import: User subscribed by import.

3: unsubscribe_bounce: Unsubscribed because the user's email bounced.

4: unsubscribe: Unsubscribed because the user submitted on an unsubscribe page. The action_id maps to the page_id, and if relevant the mailing_id, in the core_action table.

5: unsubscribe_admin: We unsubscribed them during your data import, or a staff user unsubscribed them from the individual user record.

6: unsubscribe_email: The user marked your email as spam in Gmail or another participating mail client; in Gmail users are offered the option to unsubscribe when they mark an email from a list as spam, and the unsub is sent to us as an email message. The unsubscribes from Google are not processed in real-time, however, so there can be up to a 24 hour delay before you'll see the user switch to unsubscribed. The action_id maps to the mailing_id in the core_action table; the page_id is fake but we included it to capture the mailing_id using our existing table structure.

7: subscribe_api: The user was subscribed by an action processed through the API.

8: unsubscribe_import: The user was unsubscribed through an import you did using the uploader.

9: subscribe_uploader: The user was subscribed through an import you did using the uploader.

10: unsubscribe_spamcheck: The user was unsubscribed because they failed a spam check and you've configured your instance to unsubscribe users who fail a check.

11: subscribe_notspamcheck: The user was re-subscribed by an administrator as someone who had mistakenly failed a spam check.

12: unsubscribe_reengagement: The user was unsubscribed through the list hygiene and re-engagement tools.

13: subscribe_merge: The user was subscribed through a user merge.

14: unsubscribe_merge: The user was unsubscribed through a user merge.

What triggers ActionKit to assign users to legislative districts?

Users are geocoded when they are created and when they change their address. Their legislative district information is saved in the core_location table. Read more about how legislative assignments are made here.

How are users assigned to legislative districts?

Read more under pages and users.

Can I bulk unsubscribe users?

Yes. You can unsubscribe users by importing a list of user ids or emails through the bulk uploader with the Unsubscribe users from all lists option, or you can write a simple API script to do it, e.g. by calling unsubscribe_all.

Can I subscribe users manually?

Yes. By entering their information on an ActionKit page, by importing them use the bulk uploader or by processing an action through the API. If you process an action, either by submitting for a user on an action page or through the API, the user will receive a confirmation email if you enabled that during page set up.

Can I delete a user?

Deleting users is possible with the API, but generally we don't recommend it unless it's for privacy or compliance reasons. See also Erasing users.

Keep in mind that you're only billed for mailable (subscribed, not bounced) users, though.

Can I merge two user records?

Yes. From the Users Tab under merging users.

Email address is unique for each user in ActionKit. ActionKit assigns a user_id to each new email address, whether entered by a user on an action page, imported through the bulk uploader, or added through the API.

End users can change their own email address from the user update screen. If an end user tries to change their email to one that's already in your database, the user will need to confirm by clicking a link in an email sent to the new address. The old address is unsubscribed but the two records are not merged.

What's an AKID?

The user's hashed ActionKit user and mailing ID in this format: [optional mailing id].[user_id].[hash]. For more information, see user identifier.

What type of address clean up/geocoding does ActionKit do?

If a user enters a 9 digit zip code, the zip is saved in core_user table zip field and the other 4 digits are saved to core_user.plus4.

If a user enters their address and city and a bad zip code, ActionKit will overwrite the zip code with a corrected version and add a plus 4 if we can determine the correct information.

If user enter their zip, but not an address, city or state, ActionKit will assign a state and even a city to the user. Usually a zip plus 4 is required to determine the city.

If a user enters a value in a postal code field, the value is saved to core_user.postal. If the user country='United States', the postal code is copied to the field, and if provided core_user.plus4 field. In any case, the postal code field value is left as entered.

If you copy the user_form_intl.html template into your user_form.html template, ActionKit will automatically change the postal field to a zip field if the user selects 'United States' as the country. If you or an end user enter US or USA this will be normalized to 'United States'. ActionKit only runs the processing above (and the legislative district assignments described above) where the user country='United States'.

ActionKit does not determine city or region from a postal code in another country.

ActionKit does use city, zip or postal code to assign a loc_code, which is saved in the core_location table. A loc_code is not assigned if country is the only available information. This loc_code is used for radius targeting in the mailer.

ActionKit also assigns a latitude and longitude to US or international users for whom we have a zip, postal or city. This is saved in core_location also. Lat/long is used to find events near a user.


Can I limit which staff members can see particular names?

No. ActionKit permissions are currently functional only, so for example you can stop a staff member from sending any emails or seeing the reports tab. You can't allow a user to send to a particular set of users or limit their ability to view users from the reports tab.

Targets & Delivery

How do I change the contact info for a federal legislator?

Batch delivery is available for most federal legislators. Only a handful of federal legislators have a public email address and most have moved to the use of capchas or other tests on their webforms. To work around this we purchase a database of Legislative Directors but the coverage is not 100%. You can add or edit a contact for each federal legislator by searching for the legislator on the target contact screen.

How do we target governors or committees?

This information is not built into ActionKit. To target Governors, enter them as custom targets.

You can target legislative committees by building a custom legislative target group. If you select this option, you'll be able to select the particular legislators and name and save the group you've built for future use.

How do we target new districts in the 2022 redistricting?

New district assignments are available for users in states with finalized 2022 district boundaries. This is the current list:

Congressional Districts: AL, AR, AZ, CA, CO, CT, FL, GA, HI, IA, ID, IL, IN, KS, KY, LA, MA, MD, ME, MI, MN, MO, MS, MT, NC, NE, NH, NJ, NM, NV, NY, OH, OK, OR, PA, RI, SC, TN, TX, UT, VA, WA, WI, WV

State Senate: AK, AL, AR, AZ, CA, CO, CT, DE, FL, GA, HI, IA, ID, IL, IN, KS, KY, LA, MA, MD, ME, MI, MN, MO, MS, MT, NC, ND, NE, NH, NJ, NM, NV, NY, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VA, WA, WI, WV

State House: AK, AL, AR, AZ, CA, CO, CT, DE, FL, GA, HI, IA, ID, IL, IN, KS, KY, LA, MA, MD, ME, MI, MN, MO, MS, MT, NC, ND, NH, NJ, NM, NV, NY, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VA, WA, WI, WV

The new data is stored in the core_usergeofield table. Here are the user geo field names currently in use:

  • us_district_redistrict2022: future US Congressional district
  • us_state_district_redistrict2022: future state house district
  • us_state_senate_redistrict2022: future state senate district

To report on or target users in these future districts you could use SQL like:

SELECT user_id FROM core_usergeofield
WHERE name = 'us_district_redistrict2022'
      AND value IN ('PA_01', 'PA_02');

This snippet gives the district ID in a mailing (and other places where the user object is in context):

{{ user.geofield.us_district_redistrict2022 }}

How do I customize PDFs for delivery?

When you create or edit a delivery job, you'll see a drop down for selecting the print template at the bottom of the PDF details screen. Click "manage print templates" to see a list of your available templates. To make a new template, simply copy the original.

You can customize basics (like the font and logo), the page size and margins, and the page HTML. In the Body HTML box you can edit various settings including the css that defines which fields are displayed.

How do I test signature delivery?

Sign your petition using the email on your Staff account and a constituent address to receive an example of immediate and/or batch deliveries depending on which you've set up. The subject line of the email will contain the prefix "[Batch delivery proof]" or "[Fax delivery proof]".

If you don't receive a sample delivery, confirm that you are using an address that's in the district of one of the page's targets.

How do I see the letter text a member sent?

The text of a letter or comment from Letter, Petition, and Letter to the Editor pages is stored in core_actionfield with the name comment. You can see it in the query builder by reporting on actions and displaying custom action fields with the name comment. You can also show it in confirmation emails to the user with {{ action.custom_fields.comment }}.


How do I make it easier to manage templatesets and get templateset upgrades?

With many templatesets, some clients have found it difficult to keep them all updated and accurate. A few things can help keep your templatesets manageable.

Custom page fields can handle changes in branding or donation accounts that may differ betweeen c3/c4 or microsites. Instead of adding a new templateset to maintain, consider whether a custom page field would work. See more on custom page fields for page styling.

Mirroring a parent templateset

When you don't need to change the default behavior of a template, consider replacing the contents of that template with {% include templateset/file %} to inherit the template from a master templateset. {% include %} works in both page and mailing templates.

{% include Original/signup.html %}
/* Replaces the contents of the child signup template with the Original signup template. */

When you need to change some default behavior, but only for a portion of the template, {% extends %} lets you override particular blocks in that template through Django template inheritance. Instead of replacing the contents fully, you may want to add {% extends file/path %} to the top of the file and comment out the rest. Any particular block can then be uncommented and modified.

I Set default choices for my user field. Why don’t they show up on my page?

The various fields on the page setup for a custom user field are only designed for use on ActionKit admin pages.

The Display Name is used internally to identify the custom field on the Edit content screen. The Description, Field Default, Field Choices and Field Regex items are used on the individual user record to help staff users — not end users — fill out these fields.

None of these interact with the form fields on a published action page.

Can we create a page that requires users to opt-in before they're added to a list?

Yes. Read about this in the Customizing Pages with Templates.

Can we add a thermometer or progress meter to a page hosted outside of ActionKit?

Yes. Read about re-using the existing progress meter, or developing your own, in the section on Embedding.

How do I redirect users to a donation page after they’ve signed a petition?

By default, users who take action are redirected to a thanks page located at the /cms/thanks/[PAGENAME] URL path, where they're encouraged to share the campaign on social media.

However, you can easily redirect users who've taken action on a page to a donation page instead - or to any URL, as a matter of fact - by editing the Redirect URL field in the After-action info step.

Can I hide the share buttons on a thanks page using a custom page field?

Typically, a share page includes a set of Facebook and Twitter sharing buttons. But what if you don't want them to show up on a specific page? You could create an entirely different templateset with a different Original/thanks.html template, but there is an easier way: use a custom page field.

1 Create a custom page field.

Navigate to PAGES -> Other -> Edit Custom Page Fields and click to create a custom page field. Assuming we want our share buttons to show up as default, let's name our custom page field hide_share_buttons_on_thanks_page.

Then, for our field choices, we want to put "Y" on one line to indicate "yes."

2 Edit your templateset.

In [OurTemplateset]/Thanks.html, we need to isolate the HTML blocks containing the share buttons.

Surrounding each <div class="ak-sharebox">, we need to add:

{%if page.custom_fields.hide_share_buttons_on_thanks_page == "Y" %}
{% else %}
/*Include <div class="sharebox"></div> contents here*/
{% endif %}

3 Associate the page field with the page.

Then, to hide the share buttons for a specific page, we select the templateset from step 2 and add the hide_share_buttons_on_thanks_page page field on the Action Basics screen and set its value equal to Y.

How do I add actions or donations collected offline to the goal thermometer?

You can increase the number of actions or donations reported by the page's goal thermometer by using a custom page field containing the value of the offset that should be added to the number of actions taken on the page.

Refer to this example for guidance on how to add a static offset to the goal thermometer by updating the progress_meter.html template in your templateset.

How do I display the targets on the thanks page or on the confirmation email?

For pages containing targets, you can display a list of targets on the confirmation email using the following syntax:

{% for target in action.targeted.all %} # all potential targets
        {{ target.title_full }}
{% endfor %}

On call pages, you can also display the specific the targets the user checked as having called, as well as local office targets:

{% for target in action.checked.all %} # only targets that user checked as having called
        {{ target.title_full }}
{% endfor %}
{% for office in action.local_office_checked.all %}
        Thanks for calling {{ }} in {{ }} at {{ }}.
{% endfor %}

How do I add text that only displays for people who are subscribed to a particular list?

If you want to display some text in a mailing that’s only visible to people who are signed up for a particular list, you can use ActionKit’s the Django {% if %} syntax to check whether a the subscription list's ID exists, and then use that logic to display your message.

{% if 1 in user.subscriptions.list_ids %}
    list #1 is #1!
{% endif %}

How do I prefill information on a page?

If you're filling user information (address, etc.) we strongly recommend that you use user recognition instead; that lets users share your emails without also sharing their personal information.

See Can I Set The Donation Amount Or Product Quantity Via Parameters In The URL? for details on how to prefill other data.

How do I make survey questions or user form fields appear conditionally based on user responses?

If you want to make follow-up questions appear conditionally based on the way a user answers your survey questions, check out our blog post on Conditional Survey Questions.

Donations & Products

Can I update recurring donation information?

Staff users with donation management permissions or super user status can manage recurring donations. From the user tab, search for your user by name or email then click through to the user’s action history. You’ll see an action for each time the user signed up for a recurring donation.

Click the payments link to see a summary of the user’s payments. From this screen you can cancel the commitment, refund individual payments, change the amount, the billing address and the credit card number.

Generally, we recommend directing donors to a recurring donation management page where they can update the credit card number themselves when possible.

How do I enter a check donation?

If the donor exists in ActionKit, you can upload the donation using the bulk uploader.

If the user doesn't exit in ActionKit and doesn't provide an email address, you'll need to create the user and upload the donation using a fake email address. The email address should be something with an address, which keeps our mail server from wasting time trying to deliver the emails, and keeps your bounces from being falsely inflated.

Does ActionKit calculate shipping costs?

No. Our product functionality is primarily designed for the sort of "premium-plus" model that MoveOn and others have used to give away product while simultaneously asking for donations/purchases.

ActionKit has none of the shipping, tax, or fulfillment logic that makes your life a lot, lot easier if you are doing some of your own fulfillment. In the long run, you will be much happier using a dedicated storefront site, like Shopify and then importing user data into ActionKit or integrating through our API.

How do I make a test donation?

Make a donation using your credit card or PayPal account on your donation page. You can reverse the charge from your individual user record.

We don't offer an environment for making test donations with a fake credit card number because these test set ups often use a different code path than that used by real donations from your users. Because donations are so critical we don't support this approach.

How do I allow users to choose between donations to our C3 or C4?

There are two options for switching between C3 and C4 donation accounts.

1 You can create two donation pages (one with each account type), and you can either include links between the two, or have a radio button or select box that automatically sends you between the two pages. This method makes sense if the visual differences between the C3 and C4 donation pages are substantial.

2 Alternatively, if the pages didn’t have significant design differences, you could include an HTML form element labeled “account” that lets users choose which account processor to give to. This could be a pull down, radio button, etc. Then, using javascript, you could trigger the necessary changes (e.g. adding text saying a donation was/wasn’t tax deductible, etc.) when a user selects each option.

If you’re switching between C3 and C4 accounts in Braintree, you need to write some javascript to make sure that the merchant_id passed in as an argument in the following function is correct:

window.onBraintreeDataLoad = function() {
BraintreeData.setup("MERCHANT_ID", "act", BraintreeData.environments.production);

window.onBraintreeDataLoad = function() {
BraintreeData.setup("MERCHANT_ID", "act", BraintreeData.environments.production);

Inside Original/donate.html, {{pp.merchant_id}} will automatically grab the merchant_id associated with the account you selected on the Action Basics screen.

window.onBraintreeDataLoad = function() {
BraintreeData.setup("{{ pp.merchant_id }}", "act", BraintreeData.environments.{{ pp.braintree_environment }});

window.onBraintreeDataLoad = function() {
BraintreeData.setup("{{ pp.merchant_id }}", "act", BraintreeData.environments.{{ pp.braintree_environment }});

You’ll need to replace {{ pp.merchant_id }} with your own variable that’ll change depending on which account the user selects on the donation page.

I'm not seeing donations made through PayPal in ActionKit. What could be wrong?

With ActionKit’s PayPal integration, you set up your page so users enter the amount on an ActionKit page, are sent to PayPal to confirm or enter info, then are bounced back to us by PayPal. ActionKit saves the transactions with no extra work by you. To make this work, your donation page needs to use a templateset that includes key elements of the Original/donate.html templateset file.

If you’re not seeing your PayPal donations in ActionKit, here are a few things to look at:

Are you using our PayPal integration?

Just having PayPal as an option on your page doesn’t mean you’re using our system, which feeds the data automatically into ActionKit. You need to look at two things to make sure you’re using our integration.

1 Confirm that you’ve got a PayPal account set up with ActionKit.If there’s an option for PayPal Account on the Action Basics screen for a Donation Page, you’re all set.

If you don’t have a PayPal account set up with us, you’ll need to send us your PayPal API client_id and secret credentials by filing a support ticket.

To enable the automatic import of PayPal recurring donations, you’ll need to send us a PayPal classic API username, API password and API signature. Recurring donations from PayPal are synced nightly.

Read more in the section below on importing recurring profiles from PayPal.

2 Confirm that you’re using a templateset with our integration code.

You can check this by following the PayPal link on your Donation Page. You should not be directed to an external PayPal URL to make the donation.

If you are, you need to remove the existing embedded PayPal HTML . You can instead use the PayPal processing HTML from the donate.html template in the Original templateset.

As always, you need to test your page if you’ve made significant changes to the template. Test a donation page by donating. You can reverse the donation from your user record.

You’ve confirmed that PayPal is set up correctly, but you still don’t see the donation in ActionKit.

People often use different email addresses for PayPal and ActionKit. Also, the user does not always enter an email on your donation page before donating through PayPal. As a result, there may be two email addresses associated with a PayPal donation. Of course it’s only recorded once in ActionKit.

If you’re interested, you can read how we decide which user is assigned the donation here:

For this purpose it’s just important to remember that a second email may have been used. For each PayPal donation, the email address associated with the PayPal account is recorded in the ak_paypal_email field. If you aren’t finding a donation you expect to see under a particular email, see if it’s under another user by searching the paypal email field using the advanced search on the Users Tab.

What if i’m not using ActionKit’s PayPal integration? Can I still get the donations into ActionKit?

If you don’t have PayPal integrated on your donation page, you can still import these records so they’re in your database.

The simplest approach is to import the donations by creating an Import page, and uploading a CSV or TSV file.

You can read more about how to do that here:

Imports can only be used to record donations on import pages. It’s possible to instead include these donations with your credit card donations processed through ActionKit on a donation page, but only using the REST API.

Read more here:

How do I import recurring profiles from PayPal into ActionKit?

If a PayPal recurring profile was created outside of ActionKit, you can import it into ActionKit by uploading a CSV containing columns for the recurring_id, the user_id, the donation_amount of the recurring donation, and the recurring_payment_account (whose value you can check in the select box on your donation page).


If you have more than one payment processor configured, you must include the name of the account which should be associated with the recurring profile in a column called recurring_payment_account. If you do not include this column or the value does not match one of your payment accounts, an error will be returned.

The recurring_id value should correspond to the Billing Agreement ID from PayPal.

You can find the Billing Agreement ID in your PayPal account under Reports -> “Customer Agreements” at the bottom left of the menu -> Recurring Payments -> One time Report.

After the import, updates to these recurring donations will sync nightly as long as we’ve got your PayPal classic API username, API password and API signature hooked up with ActionKit.

Can I set the donation amount or product quantity via parameters in the URL?

You can use the prefill=1 query parameter in your mailing link to trigger ActionKit’s prefill.js code, which will then look for an input name and value to prefill.

To set the “other amount” option for a donation page, you can prefill that field with a default (in this case $3) by appending this to your donation page URL: ?prefill=1&amount_other=3

Or if you want to select a specific donation button, then you can append this: ?prefill=1&amount=25 to select the $25 button.

Setting the product quantity requires knowing the ID of the product in ActionKit. Go to Pages > Donations > Products to get the ID. And then append this to your donation page URL: ?prefill=1&product_[ID]=[quantity]

So if your product ID is 15 and you want to prefill "1" into the quantity field, it would look like this: ?prefill=1&product_15=1

To default to a recurring donation, you can append this to your donation page URL: ?prefill=1&donation_type=recurring. You can also combine this with the amount or amount_other parameters, like ?prefill=1&donation_type=recurring&amount_other=10.

I want to use a multiplier on a user's highest previous contribution in order to calculate their ask amount. How do I do that?

In general, we suggest that you check out the Suggested Ask feature, as that will give you the ability to set normal-looking ask amounts (like $5, $25) based on a user’s prior giving history.

However, if you do want to do a straight out multiplication of their highest previous contribution, then you can use a mailing link formatted like so:{% requires_value donations.highest_previous_all %}{{ donations.highest_previous_all|multiply:"1.5"|floatformat:"0" }}&prefill=1

Which multiplies the user's highest previous donation by 1.5, rounds it to the nearest integer, and prefills that amount into the "other amount" field on your donation page.


Can I delete actions in ActionKit? What about tags or user fields or pages?

You can delete most actions from the individual user record. Just click on the 'action history' link and then use the 'delete' link for the particular action.

Any action without a 'delete' link and other ActionKit objects like tags, user fields and pages can only be hidden, not deleted.

When an object is hidden it is also disabled. For example, if you hide a page, users will not be able to submit on that page. Be careful not to hide objects that are currently in use.

Do you save email addresses entered into the TAF tool?

No. Since the emails entered in the TAF tool are not those of users who have taken action on one of your pages, we don't save them. But when someone takes action from a TAF link, we will then add that person as a subscriber (with user source 'taf').

How do I update our progress report dashboards to count only designated "member actions"?

ActionKit lets you indicate which actions should be counted on a page-by-page basis via the Include In Reports of Member Actions checkbox on the Action Basics screen.

The checkbox is reflected in a new real_actions column in the core_page table.

If your reports don’t take into account the real_actions column, here’s how you can update them:

FROM core_action a
JOIN core_page p ON (a.page_id =
WHERE p.real_actions = 1;

In other words, you’ll need to join core_action with core_page and find all the counts where core_page.real_actions is equal to 1.

For example, let’s update the progress report on the home page to reflect real actions.

To do so, we’ll have to edit our action_takers report by adding the following, as highlighted:

FROM core_action a
JOIN core_page p ON (a.page_id =
WHERE p.real_actions = 1
AND page_id = {page_id}
AND status    = 'complete';

Now the progress report on the home page will be updated to reflect the real count of actions:

You can also use the query builder to filter for real_action values. In the query builder, real actions are called member actions:

How do I get a list of everyone who took action on a page? What about their comments, survey responses, etc.?

ActionKit gives you an easy way to download CSVs of action takers for any page type including surveys, petitions, signups, and donations.

  1. Simply click on Download Actions from the right-hand menu of the Reports tab.
  2. Then select your page and click Download Actions.

You’ll get a CSV showing the date, user ID and the values the user submitted in any action fields for every action taken on the page.

Petition comments and survey question responses are both saved as action field values so these are included automatically.

Use the other selections shown above if you’d like include other information like the user’s email and contact information, their custom user field entries, or the source of the action. You can also limit the date range for actions returned.


What's the difference between all the custom field types?

ActionKit has five types of custom fields:

Custom action fields are assigned to each action. They are often used to hold the results of survey questions. They don't need to be setup ahead of time. Just adding a form field that starts with action_ is enough. For example, you could add the following to a sign up page to allow users to enter their mood when they signed up:

Your mood today: <input type="text" name="action_mood">

Responses are recorded in the core_actionfield table.

On the other hand, the other four types of custom fields need to be defined in advance, and may need tobe added to your templates to control how they will be displayed.

Custom user fields have one entry per user. This is different from action fields which have a value per action.

For example, you could create a favorite_color user field and collect data in a form like:

Your favorite color: <input type="text" name="user_favorite_color">

The table for these is core_userfield.

A custom page field is a custom attribute for a page. It could be something like tag_line which your editors could use during page setup to add additional content to the page. The key here is that a custom page field has a single value for the page itself.

A custom templateset field is a custom attribute for a templateset. It could be something like background_color which your administrator could use during site setup to affect the look of the page. A custom templateset field has a single value for the templateset, which is shared by all pages that use that templateset.

Finally a custom mailing field is a custom attribute for a mailing. It could be something like ask_type which your analysts could use when generating reports to compare a mailing with similar messages. A custom mailing field has a single value for a mailing.

Can I add another domain name to my site?

Yes! An additional domain name, sometimes called a vanity domain, works easily with ActionKit. Set up a CNAME DNS record that points the new domain to [[SHORTNAME]], and then file a support ticket (or follow up on this one) with the new domain name. Check your existing ActionKit URL's DNS records to find the shortname for your ActionKit instance, or ask Support.

How do I set a favicon for my site?

You can set a favicon by adding a link tag to the <head> section of your wrapper template that points to your desired icon image:

<link rel="shortcut icon" type="image/png" href="">

How do I pass through a source code to a redirect URL?

As of 2.5.23 (March 2024), you can use snippets directly in your after-action redirect URLs.

You can also use a redirect URL as a workaround.

You can set a hidden form field of redirect to specify the redirect URL. This will override the default redirect URL set on the ActionKit after-action info page. Make sure this hidden form field is placed within the existing form statement, between <form> and </form>. You can make that edit in the templateset or by including a hidden input in the page Introduction Text using the code editor mode.

In the example below the user would be redirected to even if you have something else set in ActionKit as the redirect URL.

<input type="hidden" name="redirect" value="">

To append the source code, grab the source from the query string with {{ args.source }}. You could also use JavaScript to add it to the URL and set the value of the redirect field.

<input type="hidden" name="redirect" value="{{ args.source }}">

What's an easy way to redirect users on a page?

You can easily redirect users landing on any page in ActionKit by creating a custom page field called "redir" and applying it to a page. The value of the field should be the URL you want to redirect your users to.

How do I use report parameters to see results in multiple congressional districts?

We do have some support for reports that take multiple parameters, but only for parameters like event_id, page_id, etc.

For parameters that aren't supported (where you can't type to search), you can use REGEXP and format your list of congressional districts as a regular expression. For example, "IN_04|NY_01|NJ_01" would match those three districts in a query like:

SELECT us_district, COUNT(*) from core_location WHERE us_district REGEXP {{ district }} GROUP BY 1

How do I display the number of referrals a user's sharing has generated?

You can display a user's total shares, number of referral clicks, and number of referral actions they've generated.

"Total Shares" includes Facebook and Twitter shares, as well as Tell-a-Friend (TAF) messages sent via the ActionKit system from an after-action page or an event dashboard. This count does not include the number of times a TAF link from the clipboard on the after-action page was copied/pasted.

"Total Referral Clicks" and "Total Referral Actions" include Facebook and Twitter shares, TAF messages sent via the ActionKit system, AND clicks + actions taken on copied/pasted links from the TAF clipboard on the after-action page.

The three places you can display these counts are in a confirmation email, on an after-action thanks page, and on a mailing.

Total Shares: {{ user.stats.share_count }}
Total Referral Clicks: {{ user.stats.share_clicks }}
Total Referral Actions: {{ user.stats.share_actions }}
Total Facebook Shares: {{ user.stats.share_fb_count }}
Total Twitter Shares: {{ user.stats.share_tw_count }}

How do I let end users upload files (e.g. images) to ActionKit pages?

Add a survey question or user-form field with a question type of "File Upload".