Build a Mailchimp Subscribe Form in Next.js
Create and embed a simple Mailchimp subscription form on your Next.js site to build your audience list.
In this guide, I'l show you how to create a simple Mailchimp subscribe form component that will look something like this:
Along with a Next.js api route, this form can be used to add subscribers to your Mailchimp audience lists. This solution will also allow you to customize success and error states.
Best of all, this component can be embedded and reused so you can collect email subscribers anywhere/everywhere throughout your app.
1. Get MailChimp Credentials
- Get the following credentials from Mailchimp account:
API_KEY
can be found, or created, in your Mailchimp account Extras > API KeysAUDIENCE_ID
can be found from your Mailchimp audience dashboard under Manage Audience > Settings, and then Audience Name & Defaults. This is the audience to which all of your subscribers will be added!API_SERVER
is the specific "data center subdomain" that is used for your Mailchimp account. This can be found in a few places -- but if you have your API key from the step above, it is appeneded to the end of the key (looks likeus1
,us18
, etc.). Other ways to find this are listed in the docs.
- Create a
.env
file at the root of your project and create new environment variables:MAILCHIMP_API_KEY=<api-key-here> MAILCHIMP_API_SERVER=<api-server-here> MAILCHIMP_AUDIENCE_ID=<audience-id-here>
2. Set Up Your Form
- Create a form component
components/SubscribeForm.tsx
. This will contain the subscriber's first name and email fields, and/or any other fields you want to collect:// SubscribeForm.tsx export const SubscribeForm = () => { return ( <form onSubmit={subscribeUser} className="grid gap-3 grid-flow-row md:grid-flow-col md:w-fit" > <label className="inline-grid text-sm text-gray-600 leading-[2]" htmlFor="FNAME" > First Name <input className="bg-blue-50/60 px-2 border-b-2 p-1 border-gray-400 text-gray-900 text-xl rounded-none min-w-[240px] leading-10 focus:outline-none focus:border-blueAccent" id="FNAME" type="text" name="name" required /> </label> <label className="inline-grid text-sm text-gray-600 leading-[2]" htmlFor="EMAIL" > Email <input className="bg-blue-50/60 px-2 border-b-2 p-1 border-gray-400 text-gray-900 text-xl rounded-none min-w-[240px] leading-10 focus:outline-none focus:border-blueAccent" id="EMAIL" type="email" name="email" required /> </label> <Button variant="secondary" type="submit" className="md:leading-[0.95rem] mt-4 md:mt-0" > Subscribe </Button> </form> ); }
- Add types based on the fields in your newly created form. Important: the
email
andname
entries in theFormElements
interface correspond with the inputname
attributes from the form above:// SubscribeForm.tsx interface FormElements extends HTMLFormControlsCollection { email: HTMLInputElement; name: HTMLInputElement; } interface SubscribeFormElement extends HTMLFormElement { readonly elements: FormElements; }
- Add a form submission handler. The
subscribeUser
function below gets the form field values andPOST
s them to the/api/subscribe
route, which we will create in a moment:// SubscribeForm.tsx ... export const SubscribeForm = () => { const subscribeUser = async ( e: React.SyntheticEvent<SubscribeFormElement> ) => { e.preventDefault(); const res = await fetch("/api/subscribe", { body: JSON.stringify({ email: e.currentTarget.elements.email, name: e.currentTarget.elements.name }), headers: { "Content-Type": "application/json", }, method: "POST", }); if (res.status === 201) { // Custom behaviour on success (like a success message) console.log("success"); } else { // Custom behaviour on error (like an error message) console.log("error"); } }; ...
- Optionally, replace the success and error console logs with your own custom behaviour. This could include showing a message, a banner, a toast, and much more.
- Note: The form takes advantage of native HTML form validation, so this function triggers only on valid submissions.
3. Set Up API Route
- Install the
@mailchimp/mailchimp_marketing
module via yarn or npm. - Create a file
pages/api/subscribe.ts
- Set up mailchimp client:
// subscribe.ts import type { NextApiRequest, NextApiResponse } from "next"; const client = require("@mailchimp/mailchimp_marketing"); client.setConfig({ apiKey: process.env.MAILCHIMP_API_KEY, server: process.env.MAILCHIMP_API_SERVER, }); ...
- Create the handler for this api route:
... export default async function handler( req: NextApiRequest, res: NextApiResponse ) { const { email, name } = req.body; if (!email || !name) { return res.status(400).json({ error: "Email and name are required" }); } try { const response = await client.lists.addListMember( process.env.MAILCHIMP_AUDIENCE_ID, { email_address: email, merge_fields: { FNAME: name, }, status: "subscribed", tags: ["portfolio"], } ); if (response.status >= 400) { return res.status(400).json({ error: `There was an error subscribing to the newsletter.`, }); } return res.status(201).json({ error: "" }); } catch (error) { return res .status(500) .json({ error: (error as Error).message || (error as Error).toString() }); } }
- This handler will create a new audience member with the submitted first name (FNAME), email address. The handler also sets the member as "subscribed" status and tagged with "portfolio"
More
You can capture more fields and merge fields as outlined by Mailchimp's Marketing API and Merge Fields docs. If you do add/change fields, be sure to make the corresponding updates in both the SubscribeForm.tsx
and subscribe.ts
files.
Last Thougts
You now have a small, lightweight subscribe form component that can be embedded anywhere in your app. Add it to your "about" page, at the end of your blog posts, on your personal portfolio page, in a banner.