How to open an Impact Stack action from a non-Impact Stack webpage

In some cases, you might want to have Impact Stack form on your website. We nearly always advise against having a full Impact Stack form embedded as an iframe on your website. There are significant benefits to using the streamlined Impact Stack forms on a standalone page without distracting elements on the page such as menus with links to other pages.

Having said that, there are reasons that some organisations would want to have a button or a form on their main website that can act as a starting point for a supporter completing one of their Impact Stack forms.

This page gives you some approaches to adding a button or a form on another website that a supporter can interact with and start using an Impact Stack form.

This is a page is aimed at helping web developers and others who are comfortable with adding code to websites. The code and ideas here are meant as starting point that you can build from. You almost certainly won't just copy and paste the code blocks here straight on to a page on your website.

Open an Impact Stack donation form using a link with pre-defined values

The simplest way to open an Impact Stack form from another website is to have a link that use our pre-population fragments. For example, add #p:donation_interval=1&p:donation_amount=10 to https://demo2.impact-stack.org/donation-2 to create https://demo2.impact-stack.org/donation-2#p:donation_interval=1&p:donation_amount=10 Link to that URL and people clicking on it will see an Impact Stack form with 'one-off' donation interval and donation amount of '10' prefilled. Donation interval must be '1', 'm', or 'y'. Donation amount must be a positive whole number.

You can find out about this approach to building a pre-population link on our help centre or you can use our toolkit to make this easier.

You don't need to include any extra Javascript for this approach. You can style the link to look like a button if you like.

Demo

CleanShot 2024-03-26 at 16.20.54.gif

 

You could have a series of links on your website that open up an Impact Stack page with different amounts and/or donation intervals and give it a level of interactivity through something like a tabs interface.

CleanShot 2024-03-26 at 17.10.18.gif

 

Here's the basic code for that.

See the code
<a href="https://demo2.impact-stack.org/donation-2#p:donation_interval=1&p:donation_amount=5">
	Make a one-off €5 donation
</a>
<a href="https://demo2.impact-stack.org/donation-2#p:donation_interval=1&p:donation_amount=10"
>
	Make a one-off €10 donation
</a>
<a href="https://demo2.impact-stack.org/donation-2#p:donation_interval=m&p:donation_amount=20"
	style="
		background-color: #0070f3;
		color: white;
		border-radius: 5px;
		padding: 10px;
		text-decoration: none;
		width: fit-content;
		user-select: none;
	"
>
	Make a monthly €20 donation
</a>

 

Using a HTML <form> on a non-Impact Stack website

These next two approaches require an HTML form on a page and some extra Javascript to intercept the submission of that form, get the data from the form inputs, construct a URL that will pre-populate an Impact Stack form, and finally open that URL on a supporter's computer.

Here is an example of some Javascript that can do that. As a reminder, this page is aimed at helping web developers. The code below is meant as starting point that you can adapt and as an example so web developers can understand the approach we're describing. You almost certainly won't just copy and paste the code straight on to a page on your website. Read it and adapt it to your needs. Test anything you do with this code very thoroughly.

 

See the code
<script>
document.addEventListener("DOMContentLoaded", () => {
// Feel free to choose another selector to find the forms on your page const forms = Array.from(document.querySelectorAll("form.impact_stack"));
if (forms.length === 0) { console.error("No forms were found."); return; }
for (const form of forms) {
if (form === null || !(form instanceof HTMLFormElement)) { return; }
form.addEventListener("submit", (event) => { event.preventDefault();
if (event.target === null || !(event.target instanceof HTMLFormElement)) { return; }
try { const formData = new FormData(event.target); const actionURL = new URL(event.target.action);
// This makes a pre-population link for Impact Stack: // https://support.impact-stack.org/hc/en-us/articles/115001868166-How-to-pre-populate-forms // The 'keys' here are from the 'name' attribute on the form inputs.
// They should match the 'form key' on your Impact Stack form
actionURL.hash = Array.from(formData.entries()) .filter(([, value]) => typeof value === "string") .map(([key, value]) => {
// Validation checks. You could adjust these or add any other checks you need here // Donation interval must be 1, m or y
if (key === "donation_interval" &&!["1", "m", "y"].includes(value)) { throw new Error(`Invalid donation_interval value: ${value}`); }
// Donation amount must be an integer greater than 0 if (key === "donation_amount" && (!Number.isInteger(Number(value)) || Number(value) <= 0)) { throw new Error(`Invalid donation_amount value: ${value}`); }
return `p:${encodeURIComponent(key)}=${encodeURIComponent(value)}`; }) .join("&");
window.open(actionURL.toString(), "_self"); // Use _blank to open in a new tab } catch (error) { console.error("Form submission error: ", error.message);
// You might want to show an error message on the page here } }); } }); </script>

 

Donation Form with editable amount and interval

This could be useful if you want to show the user a donation form on your main website that moves them on to an Impact Stack page. We've demonstrated a very basic donation interval picker and donation amount input. You could make this look and function however you want on your own website. Just make sure that the name attribute of your form inputs matches the relevant form key in Impact Stack. You need to include Javascript in your page that handles the form submission and opens an Impact Stack form such as that shown above.

Demo

CleanShot 2024-03-26 at 16.25.51.gif

See the code
// Make sure you have Javascript such as in the demo above
<form
class="impact_stack"
action="https://demo2.impact-stack.org/donation-2"
>
<label for="donation-interval">Donation Interval</label>

<select
id="donation-interval"
name="donation_interval"
>

<option value="1">One-off</option>
<option value="m">Monthly</option>
<option value="y">Yearly</option>

</select>

<label for="donation-amount">Donation Amount</label>
<input
type="number"
id="donation-amount"
name="donation_amount"
value="5"
min="1"
placeholder="Donation amount"
/>

<button type="submit">Donate</button>
</form>

 

Petition or other action form

You can use this approach for text fields too. It's not limited to donation forms. This could be useful if you want people to start a form on your main website then switch them over to an Impact Stack form for submission.

This is a form with three visible inputs that can be set by the user. The name attributes of the input fields should match the form key in Impact Stack. You need to include Javascript in your page that handles the form submission and opens an Impact Stack form as demonstrated above.

 

Demo

CleanShot 2024-03-26 at 16.32.12.gif

 

See the code
// Make sure you have Javascript such as in the demo above

<form
class="impact_stack" action="https://demo2.impact-stack.org/flexible-form" <label for="first-name">First Name</label> <input id="first-name" type="text" name="first_name" placeholder="First name" required="required"> <label for="last-name">Last Name</label> <input id="last-name" type="text" name="last_name" placeholder="Last name" required="required"> <label for="email">Email</label> <input id="email" type="email" name="email" placeholder="Email" required="required"> <button type="submit">Add your name</button>
</form>

 

Adding a progress bar

You could also show a progress bar with the current number of actions taken on an Impact Stack action or actions on a non-Impact Stack website.

So from this Impact Stack action…

 

...you could have a progress bar on another website that re-uses the number of signatures from Impact Stack. (Obviously this is a very bare-bones demo that hasn't been styled to look good!)

It can work because every Impact Stack action has a separate, published page with some JSON that shows the current number of signatures. The URL uses the format ${domain}/node/${nodeID}/polling – for example, at https://demo2.impact-stack.org/node/216/polling.

Again, here is some demo code for web developers to understand and re-work for their own needs. It uses clientside Javascript to fetch the current number of signatures from an Impact Stack page. You could rework the same idea for your own system that might be server-rendered. It uses the HTML <progress> element for the progress bar.

 

See the code
<label for="progressBar">
<span id="signaturesText">0 people have</span> taken the action so far
</label>
<progress id="progressBar" max="100"
value="0"
></progress>

<script>
document.addEventListener("DOMContentLoaded", () => {
// You might want to hide the progress bar and only show it again once the data is fetched
// You also might want to animate the progress bar like we do on Impact Stack

updateProgressBar();
/**
* Update a progress bar based on the number of signatures fetched from Impact Stack
* Changes the text of the progress bar and the value of the progress bar based on the number of signatures * The text of the progress bar is updated to "1 person has" or "N people have" depending on the number of signatures
* The maximum value of the progress bar is updated to the number of signatures divided by 0.9 so the progress bar is always 90% full
*/

async function updateProgressBar() {
const signaturesText = document.getElementById("signaturesText"); // Adjust the selector if needed
const progressBar = document.querySelector("progress#progressBar"); // Adjust the selector if needed
if (signaturesText === null || progressBar === null || progressBar instanceof HTMLProgressElement === false) {
console.error("Signatures text or progress bar not found.");
return;
}
const signaturesNumber = await fetchSignatureNumberFromImpactStack(
// Adjust the domain as needed
"https://demo2.impact-stack.org",

// Adjust the node IDs as needed
["216"]
// ["216", "224"]
);
if (signaturesNumber === null) {
console.log("Failed to fetch number");
return;
}

// Formatting the number of signatures to display
const formattedSignaturesNumber = new Intl.NumberFormat(
"en-GB"
// Adjust the locale if needed
// "de-DE"
).format(signaturesNumber);
if (signaturesNumber === 1) {
signaturesText.innerText = `${formattedSignaturesNumber} person has`; // Adjust the text if needed
} else {
signaturesText.innerText = `${formattedSignaturesNumber} people have`; // Adjust the text if needed
}
progressBar.max = signaturesNumber / 0.9; // This will set the maximum value so that the progress bar is always 90% full
progressBar.value = signaturesNumber;

}
/**
* Fetches the signature number from Impact Stack from an array of node IDs
*
* @param {string} domain - The Impact Stack domain
* @param {string[]} nodeIDs - An array of node IDs to fetch the signature number for
* @returns {number|null} The signature number, or null if an error occurred
*/

async function fetchSignatureNumberFromImpactStack(domain, nodeIDs) {
let signaturesNumber = 0;
for (const nodeID of nodeIDs) {
const url = `${domain}/node/${nodeID}/polling`;

try {
const response = await fetch(url);

if (!response.ok) {
console.error(`HTTP error! status: ${response.status}`);
return null;
}
const data = await response.json(); const number = data.pgbar.pgbar_default[0]; // The route to the data signaturesNumber += number;
} catch (error) {
console.error(
`There was a problem fetching the data from ${url}: ${error}`
);
}
}

return signaturesNumber;
}

});
</script>
Have more questions? Submit a request