How to Bulk Generate and Send Personalized Invitations from a CSV File Using Bannerbear and WhatsApp Cloud API (Node.js)

Learn how to bulk-generate and send personalized WhatsApp invitations using Bannerbear and the WhatsApp Cloud API! Automate image creation and deliver beautifully customized invitations at scale from a CSV file.
by Josephine Loo ·

Contents

    When it comes to sending invitations for personal events, WhatsApp beats email hands down. Email feels formal and can easily get lost in a busy inbox, while WhatsApp is where people chat daily with family and friends (WhatsApp’s open rate is over 90%, compared to just around 20% for emails!). It’s also more casual and instant. Guests can reply and confirm attendance straight from the chat, or ask questions if they have any.

    If you’re building applications like wedding planners, event organizers, or invitation platforms, integrating this kind of feature can add a warm, personal touch while keeping things automated:

    • The user uploads a CSV file with guest names and phone numbers.
    • Your app automatically generates personalized invitation messages with images for each guest.
    • Then, it sends the invites directly to guests via WhatsApp.

    Example

    Screenshot 2025-10-29 at 5.12.19 PM.png

    In this tutorial, we’ll walk you through how to build this feature. We’ll use Bannerbear for generating the invitation images and the WhatsApp Cloud API to send them out.

    🐻 Bear Tip: We’ll use a wedding invitation as the example, but you can easily adapt the same setup for customers’ birthdays, company events, or even promotional messages.

    What is Bannerbear

    Bannerbear is an API that lets you automatically generate custom images, videos, and more from templates. It provides SDKs for Node.js, Ruby, and PHP, making it easy to integrate automated image generation into any project, including this one.

    To generate images automatically, you need to create a design template that serves as a blueprint for creating the images in Bannerbear. A design template can consist of:

    • Static objects - These remain the same in every generated image (e.g., a logo)
    • Dynamic objects - These change based on data you provide (e.g., names, images)

    Here’s an example of a Bannerbear design template:

    By passing different data to the API, you can alter the values of the dynamic objects and automatically generate personalized images for each guest, showing their name on the invitation.

    Pre-requisites

    For this tutorial, you’ll need:

    How to Bulk Generate and Send Personalized Invitations from a CSV File

    Step 1. Create a Meta App

    Go to the Meta Developer Apps dashboard and create a new app:

    Screenshot 2025-10-24 at 12.58.30 PM.png

    Fill in the information needed for your app:

    Screenshot 2025-10-24 at 1.01.37 PM.png

    When asked to select a use case for the app, choose “Create an app without a use case” :

    Screenshot 2025-10-24 at 1.03.01 PM.png

    For the business portfolio, select “I don’t want to connect a business portfolio yet” :

    Screenshot 2025-10-24 at 1.03.25 PM.png

    After completing the app creation, click on the app on your Apps Dashboard and add the WhatsApp product to your app:

    Screenshot 2025-10-24 at 1.05.10 PM.png

    From the side panel, go to WhatsApp → API Setup and generate an access token:

    Screenshot 2025-10-24 at 1.28.57 PM.png

    Copy the access token and your phone number ID somewhere safe. We will need it in the code later.

    🐻 Bear Tip: A test number will be automatically created. You can use it to send a test message to your phone number to test the API.

    Step 2. Create a WhatsApp Message Template (with Header Image + RSVP Button)

    To send a message to the guests, we need to use an approved message template.  Go to WhatsApp Manager → Message templates → Manage templates and create a new message template:

    Screenshot 2025-10-24 at 2.04.04 PM.png

    Choose “Default” for your template category and click “Next” to continue:

    Screenshot 2025-10-24 at 2.03.53 PM.png

    Then, fill in the information needed, including the message body and variables:

    Screenshot 2025-10-28 at 5.10.54 PM.png

    To allow guests to RSVP to the invitation, add a button with an appropriate URL:

    Screenshot 2025-10-28 at 5.24.20 PM.png

    Finally, submit the template for review.

    🐻 Bear Tip: Before you can use the template, you’ll need to wait for it to be reviewed and for its status to be updated to “Active”.

    Step 3. Create a Bannerbear Template

    Head to your Bannerbear dashboard and create a new template. You can create one from scratch by clicking “Create a Template” from your project page:

    …or use a pre-made template from Bannerbear’s Template Library, like this one (click on it to duplicate to your project):

    Bannerbear Floral Watercolor - Wedding Invitation template

    The template contains dynamic objects like recipient_name, time_date, location, etc.:

    Screenshot 2025-10-28 at 2.39.10 PM.png

    The values of these objects can be changed using Bannerbear’s API to generate different images.

    Once you’ve created your template, click on the three dots at the top right corner to see your template ID:

    Screenshot 2025-10-28 at 2.56.43 PM.png

    Copy and keep it somewhere safe.

    Do the same for your API key:

    Screenshot 2025-10-28 at 2.57.14 PM.png

    Step 4. Write the Code

    In your terminal/command prompt, run the commands below to create a new project and initialize a new Node.js project in it:

    mkdir whatsapp-invites
    cd whatsapp-invites
    npm init
    

    🐻 Bear Tip:  If you already have an existing project, skip this step and only add the relevant code to your codebase.

    Then, run the command below to install the packages needed:

    npm install bannerbear csv-parser
    

    To demonstrate how the flow works, we’ll create a script that reads guest data from a CSV file, sends the details to Bannerbear to generate personalized images, and then delivers those images along with a personalized message to each guest listed in the CSV.

    Create an .env file and store your Bannerbear and WhatsApp credentials there:

    BANNERBEAR_API_KEY=your_bannerbear_api_key
    BANNERBEAR_TEMPLATE_ID=your_bannerbear_template_id
    WHATSAPP_TOKEN=your_whatsapp_token
    WHATSAPP_PHONE_NUMBER_ID=your_whatsapp_phone_number_id
    

    Then, create a file named index.js and add the code below:

    readGuestsFromCSV()

    require('dotenv').config();
    const fs = require('fs');
    const csv = require('csv-parser');
    
    function readGuestsFromCSV(filePath) {
      return new Promise((resolve, reject) => {
        const guests = [];
        fs.createReadStream(filePath)
          .pipe(csv())
          .on('data', (row) => {
            if (row.name && row.phone) { // Expected CSV columns: name, phone
              guests.push({
                name: row.name.trim(),
                phone: row.phone.trim(),
              });
            }
          })
          .on('end', () => {
            console.log(`Loaded ${guests.length} guests from CSV`);
            resolve(guests);
          })
          .on('error', (err) => {
            reject(err);
          });
      });
    }
    

    This function reads the guests’ names and phone numbers from the CSV file with column names: name and phone, and returns them as an object.

    createInviteImage()

    const { Bannerbear } = require('bannerbear');
    ...
    async function createInviteImage(guestName) {
      const bb = new Bannerbear(process.env.BANNERBEAR_API_KEY);
      const image = await bb.create_image(
        process.env.BANNERBEAR_TEMPLATE_ID,
        {
          modifications: [
            {
              name: 'recipient_name',
              text: guestName,
            },
          ],
        },
        true
      );
    
      console.log(`Image created for ${guestName}:`, image.image_url);
      return image.image_url;
    }
    

    This function creates personalized images for the guests with their names on them using Bannerbear and returns the image URL.

    sendTemplateWithImageURL()

    async function sendTemplateWithImageURL(imageUrl, guestName, guestPhone) {
      const WHATSAPP_TOKEN = process.env.WHATSAPP_TOKEN;
      const PHONE_NUMBER_ID = process.env.WHATSAPP_PHONE_NUMBER_ID;
      const url = `https://graph.facebook.com/v20.0/${PHONE_NUMBER_ID}/messages`;
    
      const payload = {
        messaging_product: 'whatsapp',
        to: guestPhone,
        type: 'template',
        template: {
          name: 'wedding_invitation',
          language: { code: 'en' },
          components: [
            {
              type: 'header',
              parameters: [
                {
                  type: 'image',
                  image: { link: imageUrl },
                },
              ],
            },
            {
              type: 'body',
              parameters: [
                { parameter_name: 'guest_name', type: 'text', text: guestName },
                { parameter_name: 'date', type: 'text', text: '1 Apr 26' },
                { parameter_name: 'time', type: 'text', text: '7:00pm' },
                { parameter_name: 'location', type: 'text', text: 'Hard Rock Hotel, Pattaya' },
                { parameter_name: 'rsvp_date', type: 'text', text: '1 Nov 25' },
                { parameter_name: 'bride_name', type: 'text', text: 'Abbey' },
                { parameter_name: 'groom_name', type: 'text', text: 'John' },
              ],
            },
          ],
        },
      };
    
      const res = await fetch(url, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${WHATSAPP_TOKEN}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(payload),
      });
    
      const data = await res.json();
      if (!res.ok) {
        console.error('❌ Send error:', data);
        throw new Error(`WhatsApp API error: ${res.status}`);
      }
      console.log(`Message sent to ${guestName}:`, data);
    }
    

    This function sends personalized invitation messages in bulk to all the guests listed in the CSV file, along with the images generated by Bannerbear.

    🐻 Bear Tip: Make sure the details match what’s shown in the image!

    Finally, put them together in a main function:

    async function main() {
      try {
        const guests = await readGuestsFromCSV('Abbey-John Wedding Guest List.csv');
    
        for (const g of guests) {
          const imageUrl = await createInviteImage(g.name);
          await sendTemplateWithImageURL(imageUrl, g.name, g.phone);
          console.log(`Invitation sent to ${g.name}`);
        }
      } catch (err) {
        console.error('Error:', err);
      }
    }
    
    main();
    

    🐻 Bear Tip: View the full code on GitHub.

    Step 5. Test the Code

    In your terminal, execute the command below to run the script:

    node index.js
    

    This will send a personalized invitation message, along with a customized image to each guest listed in the CSV file:

    Screenshot 2025-10-29 at 5.12.19 PM.png

    🐻 Bear Tip: Using a test number without a business name, like in this tutorial might confuse the guests. It’s best to send the messages from a verified WhatsApp Business account to keep it professional.

    Conclusion

    While we used a wedding invitation as an example, the same approach can easily be adapted for many other types of events and campaigns, such as:

    • Birthday or anniversary invitations
    • Corporate or networking event invites
    • Product launch announcements
    • Customer appreciation messages or VIP offers
    • Conference and webinar reminders

    With just a few tweaks to your Bannerbear template and CSV data, you can adapt this workflow to almost any use case that needs personalization at scale. If you haven’t already, sign up for Bannerbear and get 30 free API credits to try it out!

    About the authorJosephine Loo
    Josephine is an automation enthusiast. She loves automating stuff and helping people to increase productivity with automation.

    How to Use Secondary Text Styles in Bannerbear

    Secondary text styles in Bannerbear give you the flexibility to create intricate graphics without the complexity of managing multiple text layers. Here's how to set your template up with this dynamic text option.

    How to Build a Discord Bot That Creates Personalized Certificate Images For Members Using Bannerbear (Node.js)

    Learn how to build a Discord bot that sends personalized certificate images using a member’s name and avatar image. Celebrate member milestones, achievements, and good news with this bot and increase engagement in your Discord community!

    5 Subtle, Minimal Text Background Ideas (+ Free Bannerbear Templates!)

    Text backgrounds are powerful design elements that create hierarchy, add dimension, and reinforce branding in your graphics, documents, and videos. Learn how to customize your Bannerbear text layers in this guide!

    Automate & Scale
    Your Marketing

    Bannerbear helps you auto-generate social media visuals, banners and more with our API and nocode integrations

    How to Bulk Generate and Send Personalized Invitations from a CSV File Using Bannerbear and WhatsApp Cloud API (Node.js)
    How to Bulk Generate and Send Personalized Invitations from a CSV File Using Bannerbear and WhatsApp Cloud API (Node.js)