Integration 8 min read

How to Send WhatsApp Messages from Wix Forms Using Zaple.ai

A clean, secure, and production-ready guide using Wix Velo.

Are you looking for a reliable way to instantly engage with your website visitors the moment they reach out?

If you're using Wix Forms V2 and want to automatically send a WhatsApp template message after a successful form submission, you're in the right place. In this guide, we'll walk you through a clean, secure, and production-friendly setup using Zaple.ai and Wix Velo.

By connecting your Wix form to Zaple.ai's powerful API, you can instantly follow up with leads, confirm event registrations, or send rich media like images and documents directly to their WhatsApp.

Let's build the integration with Wix's official backend form event so the workflow remains practical without exposing customer data or Zaple credentials in the browser.

Why Connect Wix Forms to WhatsApp?

In today's fast-paced digital world, email follow-ups often get lost in spam folders. WhatsApp, boasting a 98% open rate, helps businesses engage leads quickly in a channel customers check throughout the day.

With this integration, you achieve:

  • Instant Lead Engagement: Strike while the iron is hot by messaging users right after they submit an inquiry.
  • Secure Architecture: Keep your API keys hidden on the backend using Wix Secrets Manager.
  • Rich Media Support: Zaple's v3 API allows you to send stunning templates with image headers and dynamic variables seamlessly.

What We Are Building: The Integration Flow

  1. A visitor submits your Wix Forms V2 form.
  2. Wix stores the submission and fires its official wixForms_onSubmissionCreated() backend event.
  3. The event handler maps the required fields and verifies the WhatsApp consent field.
  4. A private Wix Data collection prevents duplicate sends for the same submission.
  5. The backend retrieves your Zaple credentials from Wix Secrets Manager.
  6. A POST request triggers Zaple’s v3 template-message API.
  7. Record the accepted API response, then monitor the message's asynchronous delivery state.

Prerequisites

Before we write any code, ensure you have the following ready:

  • A published Wix site with Velo (Dev Mode) enabled.
  • A Wix Forms V2 form embedded on a page.
  • An active Zaple.ai account.
  • An approved WhatsApp template in your Zaple dashboard.
  • Your Zaple Template ID.
  • A public image URL (if your template features a media header).

Step 1: Securely Store Your Zaple API Secrets in Wix

Never hardcode API keys in your frontend code. Using Wix Secrets Manager ensures your credentials stay secure.

Go to your Wix Dashboard → Settings → Secrets Manager and create these two secrets:

  • Zaple_API_Key
  • Zaple_API_Secret

Step 2: Configure Your Wix Page Code (Frontend)

Open your Wix Editor, turn on Dev Mode, and select your form page. Frontend code should only manage the confirmation UI; it must not call a credential-backed message sender or log submitted fields.

Add the following code to your page:

javascript
$w.onReady(function () {
    // Frontend code may update the confirmation UI after Wix saves the form.
    // Do not send the Zaple request or log submitted fields here.
    $w("#form2").onSubmitSuccess(() => {
        $w("#successText").show(); // Optional success-state element
    });
});

Pro Tip: We use onSubmitSuccess() because it only runs after the server has completely and successfully received the submission.

Step 3: Connect the Wix Backend Form Event

In your Wix site's Backend section, create or open events.js. Wix Forms V2 fires wixForms_onSubmissionCreated() after a submission is created. Replace the form ID and field keys with the values from your form:

javascript
// backend/events.js
import { sendThankYouMessage } from "backend/zaple";

export async function wixForms_onSubmissionCreated(event) {
    const submission = event.entity;

    if (submission.formId !== "YOUR_WIX_FORM_ID") return;

    const fields = submission.submissions ?? {};

    await sendThankYouMessage({
        submissionId: submission._id,
        firstName: fields.first_name,
        rawPhone: fields.whatsapp_number_1,
        hasWhatsappConsent: fields.whatsapp_consent === true
    });
}

Next, create backend/zaple.js. Also create a private CMS collection named ZapleProcessedSubmissions; the submission ID becomes its unique record ID so a retried event cannot send twice:

javascript
// backend/zaple.js
import wixData from "wix-data";
import { fetch } from "wix-fetch";
import { elevate } from "wix-auth";
import { secrets } from "wix-secrets-backend.v2";

const getSecretValue = elevate(secrets.getSecretValue);

async function claimSubmissionOnce(submissionId) {
    try {
        // Create a private CMS collection named ZapleProcessedSubmissions.
        // The Wix submission ID is the record ID, so duplicate events fail safely.
        await wixData.insert(
            "ZapleProcessedSubmissions",
            { _id: submissionId, processedAt: new Date() },
            { suppressAuth: true }
        );
        return true;
    } catch (error) {
        if (String(error?.message ?? "").toLowerCase().includes("already exists")) {
            return false;
        }
        throw error;
    }
}

// WARNING: Keep this in a backend-only .js module. Never expose it through
// Permissions.Anyone or return credentials to frontend code.
export async function sendThankYouMessage(submission) {
        const { firstName, rawPhone, submissionId, hasWhatsappConsent } = submission;
        const phoneNumber = String(rawPhone ?? "").replace(/\D/g, "");

        if (!hasWhatsappConsent || !/^\d{7,15}$/.test(phoneNumber)) {
            throw new Error("Submission is missing consent or a valid phone number");
        }

        const accepted = await claimSubmissionOnce(submissionId);
        if (!accepted) return { success: false, reason: "duplicate_submission" };

        const url = "https://app.zaple.ai/api/v3/send-template-message";

        // Retrieve secure credentials
        const apiKeyResult = await getSecretValue("Zaple_API_Key");
        const apiSecretResult = await getSecretValue("Zaple_API_Secret");
        const apiKey = apiKeyResult.value ?? apiKeyResult;
        const apiSecret = apiSecretResult.value ?? apiSecretResult;

        // Construct the Zaple payload
        const payload = {
            template_id: "56386517725194833309742", // Replace with your template ID
            country_code: "91", // Default country code
            send_to: phoneNumber,

            // Required if your template includes a media header
            media_url_type: "public_url",
            media_url: "https://assets.zaple.ai/7/U3l6GpdzpHjShICdW2FWcmNguZ3JG5pnAubXzeTH.jpg"

            // Uncomment to pass dynamic variables, like the user's name
            // body_text1: firstName
        };

        // Send the request to Zaple
        const response = await fetch(url, {
            method: "POST",
            headers: {
                "Zaple-Api-Key": apiKey,
                "Zaple-Api-Secret": apiSecret,
                "Content-Type": "application/json"
            },
            body: JSON.stringify(payload)
        });

        const responseText = await response.text();
        // WARNING: Never log the payload or raw provider response in production.
        // They may contain phone numbers, message content, or other customer PII.
        // If operational logging is required, record only a correlation ID and status.

        if (!response.ok) {
            await wixData.remove("ZapleProcessedSubmissions", submissionId, { suppressAuth: true });
            throw new Error(`Zaple API request failed with status ${response.status}`);
        }

        try {
            const result = JSON.parse(responseText);
            return {
                success: true,
                messageId: result.message_id ?? result.data?.message_id ?? null
            };
        } catch (e) {
            return { success: true, messageId: null };
        }
}

⚠️ Do Not Expose the Send Helper

A public or member-callable Web Method backed by messaging credentials can be invoked outside the visible form and abused. The backend event above preserves the automation while keeping the credential-backed sender inaccessible to site visitors. Wix backend events run on a published site, not in normal Preview mode.

Step 4: Map Your Wix Form Field IDs Exactly

Your backend handler must map the exact field keys in the trusted Wix form-event payload for the Forms version you use.

If your output looks like this:

json
{
  "first_name": "test",
  "whatsapp_number_1": 9876543210
}

Map first_name and whatsapp_number_1 in the backend event handler, verify explicit WhatsApp consent, and pass a stable submission ID through the idempotency guard.

Step 5: Handling Media in WhatsApp Templates

If your approved WhatsApp template in Zaple has an image or document header, you must include the media fields in your payload:

javascript
media_url_type: "public_url",
media_url: "https://your-public-image-url.com/image.png"

Note: Ensure the URL used is publicly accessible and does not require authentication to view.

Step 6: Testing and Troubleshooting

Publish the site, submit one consented test form, and monitor privacy-safe status logs in the Wix dashboard. Wix backend events do not run in normal Preview mode. Verify that the trusted backend event—not the browser—invokes the helper exactly once.

What You Should See:

  • Frontend UI: a normal form success state with no provider response or submitted fields exposed.
  • Backend Logs: HTTP status, a privacy-safe correlation ID, and structured error category only—never the raw provider response.
  • Test contact: verify the consented message, then reconcile its provider status to the saved request record.

Quick Troubleshooting Guide:

  1. The backend helper never runs?
    Confirm the event or automation is attached to the correct Wix Forms version, adapt the event payload mapping, and verify that the helper stays backend-only.
  2. Backend is running, but no WhatsApp message is received?
    Check for invalid API Keys / Secrets, using the wrong template_id, or an invalid phone number format. If you are passing country_code: "91", make sure send_to only contains the 10-digit local number (e.g., 9876543210, not 919876543210).
  3. Dynamic Template Variables are blank?
    If your template says "Hi {{1}}, thank you...", you must pass body_text1: firstName in your Zaple payload. Check Zaple's template setup for exact variable indexing.

Final Thoughts

Integrating Wix Forms V2 with Zaple.ai is one of the most practical and impactful automations you can build for lead generation, event registration, and customer inquiries.

By combining Wix's backend submission event with Zaple's API, you keep credentials private while delivering a rapid, personalized WhatsApp experience. For the supported workflow and setup options, see Zaple's Wix WhatsApp integration.

Ready to Turbocharge Your WhatsApp Messaging?

Start building seamless customer journeys with WhatsApp Business API.

Frequently Asked Questions

Can I run this code without Wix Dev Mode (Velo)?

No. You need to enable Dev Mode in Wix to add custom Javascript and create the required backend Web Modules.

Why shouldn't I just make the API call from the page code?

Making the API call from the frontend exposes your private Zaple_API_Key and Zaple_API_Secret to the public. Anyone viewing your site's source code could steal your credentials and send messages on your behalf.

Do I need a paid Zaple account to do this?

You will need an active Zaple account configured with the WhatsApp Business API. Check Zaple.ai pricing for tier limits on template messages.

What if the user submits a messy phone number format?

Normalize and validate the phone number in the trusted backend handler after checking consent. Browser-side formatting may improve UX, but it is not a security boundary.