WhatsApp reminders for tomorrow's appointments

Clients get a WhatsApp reminder the day before their appointment — fewer no-shows.

Medium Saves ~8 hours/month Customer SupportBy Flowngn team

Works with n8n · Make · Zapier

How it works

Trigger: Schedule — every day at 10:00
  1. Get tomorrow's appointments from Google Calendar.
  2. Find each client's phone number in the event description.
  3. Send each client an approved WhatsApp reminder with the time.

Diagram

Every day 10:00Schedule TriggerCTomorrow's appointm…Google Calendar{ }Find client phonesCodeWSend reminderWhatsApp Business Cloud
Trigger App Code

Code

JavaScript used in the Code step — already included in the template below.

Find client phones · Code node
// Finds the client's phone number in each of tomorrow's events.
// Put it in the event description like:  Phone: +201001234567
const out = [];

for (const { json: e } of $input.all()) {
  if (!e.id) continue;
  const match = String(e.description || "").match(/phone[^+\d]*(\+?\d[\d\s-]{7,})/i);
  if (!match) continue;

  const start = e.start?.dateTime ? new Date(e.start.dateTime) : null;
  out.push({
    json: {
      phone: match[1].replace(/[^0-9]/g, ""),
      client: (e.summary || "").split(" - ")[0],
      time: start ? start.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" }) : "",
    },
  });
}

return out;

Build it

Pick your tool — same automation, step by step.

Copy and paste straight into an n8n canvas (Ctrl+V), or download and use Import from File. Then connect your own credentials and replace every YOUR_… placeholder.

Workflow JSON
Show code (155 lines)
{
  "name": "WhatsApp reminders for tomorrow's appointments (Flowngn)",
  "nodes": [
    {
      "parameters": {
        "content": "## WhatsApp reminders for tomorrow's appointments\nClients get a WhatsApp reminder the day before their appointment — fewer no-shows.\n\n**Setup**\n1. Open each node and connect your own credentials.\n2. Replace every YOUR_… placeholder.\n3. Test once, then activate.\n\nFree template from Flowngn",
        "height": 260,
        "width": 340
      },
      "id": "292c1d67-c80f-4cc7-af9e-c21711972859",
      "name": "Setup notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -420,
        -60
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 10
            }
          ]
        }
      },
      "id": "292c1d67-c80f-4cc7-af9e-c21711972859",
      "name": "Every day 10:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "operation": "getAll",
        "calendar": {
          "__rl": true,
          "value": "primary",
          "mode": "id"
        },
        "returnAll": true,
        "timeMin": "={{ $today.plus({ days: 1 }).toISO() }}",
        "timeMax": "={{ $today.plus({ days: 2 }).toISO() }}",
        "options": {
          "singleEvents": true,
          "orderBy": "startTime"
        }
      },
      "id": "292c1d67-c80f-4cc7-af9e-c21711972859",
      "name": "Tomorrow's appointments",
      "type": "n8n-nodes-base.googleCalendar",
      "typeVersion": 1.3,
      "position": [
        300,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// Finds the client's phone number in each of tomorrow's events.\n// Put it in the event description like:  Phone: +201001234567\nconst out = [];\n\nfor (const { json: e } of $input.all()) {\n  if (!e.id) continue;\n  const match = String(e.description || \"\").match(/phone[^+\\d]*(\\+?\\d[\\d\\s-]{7,})/i);\n  if (!match) continue;\n\n  const start = e.start?.dateTime ? new Date(e.start.dateTime) : null;\n  out.push({\n    json: {\n      phone: match[1].replace(/[^0-9]/g, \"\"),\n      client: (e.summary || \"\").split(\" - \")[0],\n      time: start ? start.toLocaleTimeString(\"en-GB\", { hour: \"2-digit\", minute: \"2-digit\" }) : \"\",\n    },\n  });\n}\n\nreturn out;"
      },
      "id": "292c1d67-c80f-4cc7-af9e-c21711972859",
      "name": "Find client phones",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        600,
        0
      ]
    },
    {
      "parameters": {
        "operation": "sendTemplate",
        "phoneNumberId": "YOUR_PHONE_NUMBER_ID",
        "recipientPhoneNumber": "={{ $json.phone }}",
        "template": "YOUR_REMINDER_TEMPLATE|ar",
        "components": {
          "component": [
            {
              "type": "body",
              "bodyParameters": {
                "parameter": [
                  {
                    "type": "text",
                    "text": "={{ $json.client }}"
                  },
                  {
                    "type": "text",
                    "text": "={{ $json.time }}"
                  }
                ]
              }
            }
          ]
        }
      },
      "id": "292c1d67-c80f-4cc7-af9e-c21711972859",
      "name": "Send reminder",
      "type": "n8n-nodes-base.whatsApp",
      "typeVersion": 1,
      "position": [
        900,
        0
      ]
    }
  ],
  "connections": {
    "Every day 10:00": {
      "main": [
        [
          {
            "node": "Tomorrow's appointments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tomorrow's appointments": {
      "main": [
        [
          {
            "node": "Find client phones",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find client phones": {
      "main": [
        [
          {
            "node": "Send reminder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}

Open in the playground to edit →

Tips

  • Write the client's number in the event description like: Phone: +201001234567
  • Add Confirm / Reschedule buttons to the template to cut no-shows even more.

Related flows