Behind the scenes8 min read
SMS notifications from WordPress forms
Send SMS notifications from WordPress forms: the Contact Form 7, WPForms and Gravity Forms hooks, spam, consent wording on the form, and where the key belongs.
In short
- WordPress.org listed Contact Form 7 with 10+ million active installations and WPForms Lite with 5+ million in November 2026, the two most installed form builders on its contact form tag.
- Gravity Forms documents that its gform_after_submission hook also runs for entries marked as spam, so code that texts from it has to check the entry's status first.
- WPForms says wpforms_process_complete fires only after a successful entry, once the entry is saved and email notifications are sent, and its entry id is 0 on WPForms Lite.
- The WordPress HTTP API waits for a reply by default, with a timeout of 5 seconds, so a text sent straight from a form hook can hold up the visitor's submission.
- The ICO says consent must be a positive opt-in, separate from other terms, and that pre-ticked boxes should not count as consent.

A form on a WordPress site usually ends in an email, and on a busy day that email sits unread until someone checks. SMS notifications from WordPress forms fix that in a few lines: the form plugin fires a hook when someone submits, your code catches it, and an SMS API sends the text. There are two quite different texts you might send. One goes to you, so a quote request or a booking reaches a phone straight away. The other goes to the person who filled in the form, to confirm what happens next. They need different care, and both need a form plugin hook to start from. CaptiFi Connect has no WordPress plugin, so this post works from each form plugin's documentation and our REST API.
Which plugin you have decides which hook you use. On WordPress.org's contact form tag, two form builders stand well clear of the rest.
Read 4 November 2026. WordPress.org shows installations in bands (10+ million, 800,000+), so each figure is a lower bound. Gravity Forms is sold outside the directory and is not counted. Form builders only; other plugins on the tag are left out.
Source: WordPress.org plugin directory, contact form tag
See the figures as a table
| Active installations (m) | |
|---|---|
| Contact Form 7 | 10 |
| WPForms Lite | 5 |
| Fluent Forms | 0.8 |
| Forminator | 0.6 |
| Ninja Forms | 0.5 |
| SureForms | 0.5 |
| Formidable Forms | 0.3 |
The hook for each form plugin
Each of the big three has an action that runs after a submission has been accepted. What "accepted" means differs, and spam is where it matters.
| Plugin | Hook | When it runs |
|---|---|---|
| Contact Form 7 | wpcf7_mail_sent | After validation, the spam checks and a successful email |
| WPForms | wpforms_process_complete | At the end of a successful entry, after saving and notifications |
| Gravity Forms | gform_after_submission | At the end of the submission, spam entries included |
In Contact Form 7, the source shows wpcf7_mail_sent firing only once the submission has passed its acceptance and spam checks and the email has gone, with wpcf7_mail_failed firing instead if the email fails. Inside your callback, WPCF7_Submission::get_instance() returns the submission, and get_posted_data() gives you the fields by name.
WPForms documents that wpforms_process_complete "only fires if the entry was successful and did not contain errors", and that "Saving the entry to the database and sending the email notifications are done prior to this hook running". Its first argument is $fields, described as "Sanitized entry field values/properties", which is the one to read from (the second is the raw $_POST). There's a per-form version, wpforms_process_complete_{$form_id}, so a text can follow the booking form and leave the newsletter form alone. One catch: the $entry_id argument "Will return 0 if entry storage is disabled or using WPForms Lite".
Gravity Forms needs one extra line. Its documentation says gform_after_submission "also runs for entries which are marked as spam", so check the entry's status and return early on spam, or every bot that gets past the form will text you. Like WPForms, it has a per-form variant, gform_after_submission_5 for form 5.
Alert texts to your own phone
This is the easy one, and the one most sites want. The number is yours, set once in your code, so nothing typed into the form decides who gets texted. Keep the text short and keep most of the detail in the email:
Hartley Kitchens: new quote request from J. Patel, kitchen refit, LS6. Full details in your email.
There's a reason for that restraint. Whatever someone types in a free text box can contain anything, including health details, an angry complaint or a phone number that isn't theirs, and a text shows on a lock screen. The name, the type of enquiry and a postcode district are usually enough to decide whether to ring back now. Our staff alerts page has more on texts to your own team.
If more than one person should hear about a new enquiry, to takes a list of numbers (up to 1,000 in one request), so the whole office gets the alert from a single call. Each number is a separate text and a separate credit.
Put a ceiling on it too. A form that gets past the spam checks a few hundred times in an hour will text you a few hundred times, and each of those is a credit. A transient that counts alerts in the last hour, and stops at a number you choose, costs nothing to add.
Confirmation texts to the person who filled it in
Texting the visitor is more useful, and riskier, because now the form decides who gets a text. Anyone can type a stranger's mobile number into your form, and a script can do it over and over. That's the start of SMS pumping, which our post on the fraud that targets sign-up forms covers in detail. A few habits keep it in check.
- Only text from a form that has spam protection switched on, and in Gravity Forms, skip spam entries as above.
- Send at most one confirmation to a number in a day, tracked in a transient keyed on a hash of the number.
- Keep the confirmation purely factual: what you received and what happens next.
That last point is about the law as much as tone. A text confirming someone's own booking or enquiry is a service message. Add "and 10% off your first visit" and it becomes marketing, which needs the person's consent. For example:
Hartley Kitchens: thanks, Jaya. We've got your quote request and Sam will call you by Friday.
Send it from a number (leave sender out of the request) and the visitor can answer. A reply like "Can Sam ring after 5?" lands in the two-way inbox, threaded with the confirmation, where whoever is on the phones can see it. From a sender name the same text can't be answered at all, which is fine for a bare receipt and frustrating for anything that invites a question.
Phone fields come in every format. Our API takes any common UK format and lists numbers it can't text (landlines, non-UK numbers) under rejected with a reason, uncharged, so you don't have to tidy them first.
Consent wording on the form
If the form also asks whether people want offers by text, the wording of that tick box is what your consent rests on. The ICO's guidance on valid consent is direct about it: consent must be "a positive action or indication", and "Silence, pre-ticked boxes or inactivity should not therefore constitute consent". The request should be "separate from other terms and conditions", and "you need to identify yourself". So use an unticked box of its own, mention texts by name, and name the business:
Tick if you'd like offers from Hartley Kitchens by text. You can reply STOP at any time.
The ICO adds that you "must be able to demonstrate that someone has consented". When the box is ticked, store the person as a contact through our API with the permission record filled in: POST /contacts takes consent_source (web_form, say), consent_at (the submission time) and consent_wording (the exact label they ticked, up to 2,000 characters). The record then sits with the contact. Our post on writing a consent request that stands up goes further into the wording.
Sending without slowing the form
The request itself is a wp_remote_post to https://captificonnect.co.uk/api/v1/messages with the Authorization, Content-Type and Idempotency-Key headers and a JSON body of to and body. Our post on WooCommerce SMS order notifications walks through that call and the answers to handle, so it isn't repeated here.
What differs for forms is timing. WordPress's HTTP API is blocking by default ("Whether the calling code requires the result of the request", default true), with a timeout of 5 seconds, and the form hooks run while the visitor waits for the thank-you message. You have two ways out.
Setting blocking to false sends the request and returns at once, but you never see the answer, so an empty balance (our 402) or a refused number goes unnoticed. The better route is to schedule the send with wp_schedule_single_event for a few seconds ahead and do the work in that event. Bear in mind how WP-Cron runs: the handbook says it "is only triggered on page load", and warns that a task scheduled for 2:00PM may wait if "no page loads occur until 5:00PM". On a quiet site, that's a reason to point a real server cron job at wp-cron.php, or to use Action Scheduler as the WooCommerce post does.
Give each send an Idempotency-Key so a duplicate event, or a visitor who double-clicks submit, can't send two texts. Gravity Forms gives you an entry id to build it from. WPForms Lite returns 0, and Contact Form 7 has no entry id at all, so build the key from a hash of the submitted fields and the form id. Two identical submissions then share a key, which is exactly what you want. Our post on sending a text exactly once explains the header.
Where the API key goes
Not in the options table. Plugin settings screens save to wp_options, where any other plugin can read the value and every database backup carries it. Define the key as a constant in wp-config.php and read the constant in your code; the WooCommerce post above has the detail, and our post on keeping API keys safe covers rotation. On a staging copy of the site, put a cc_test_ key in the same constant. Test sends go through the same checks, cost nothing, reach no phone and still fire our webhooks, so you can submit the form fifty times without texting anyone.
Common questions
Can Contact Form 7 send an SMS?
Not on its own; it sends email. A few lines of code hooked to wpcf7_mail_sent can call an SMS API after each successful submission, reading the fields through WPCF7_Submission. That hook runs only after the spam checks and the email have succeeded.
How do I get a text when someone fills in my WordPress form?
Hook into your form plugin's after-submission action (wpcf7_mail_sent, wpforms_process_complete or gform_after_submission) and send a text to your own mobile from there. Keep the text short, put a cap on how many it can send in an hour, and leave the full details in the email.
Do I need consent to text someone who filled in my contact form?
Not for a factual reply about their own enquiry or booking, which is a service message. To send offers or other marketing by text, you need their consent, given by ticking an unticked box that mentions texts and names your business.
Why does Gravity Forms send texts for spam entries?
Gravity Forms runs gform_after_submission for entries marked as spam as well as genuine ones, as its documentation says. Check the entry's status in your callback and stop if it is spam, before any text is sent.
Sources
Read for this post on 4 November 2026.
- WordPress.org: plugins tagged contact form, with active installations
- Contact Form 7 source: includes/submission.php (wpcf7_mail_sent)
- WPForms developer docs: wpforms_process_complete
- Gravity Forms documentation: gform_after_submission, modified 23 July 2026
- WordPress developer reference: WP_Http::request() arguments
- WordPress plugin handbook: Cron
- WordPress developer reference: wp_schedule_single_event()
- ICO: What is valid consent?
- CaptiFi Connect: API reference (contacts and messages)
Written by the CaptiFi Connect team. Published 4 November 2026. More in Behind the scenes
Send your first text this week
Set up your account and contacts now. Until we've approved it, a person reads each text before it goes out.