If you run WordPress sites for clients who also use Go High Level (GHL), you’ve probably hit this roadblock: how do you get form submissions into GHL campaigns automatically?
Manually exporting and importing CSVs is messy. Third-party tools can feel like overkill. So I wrote GHL Email Integration — a small WordPress plugin that solves this problem directly in PHP.
In this post, I’ll break down the design, show some code examples, and explain how it all works.
The Problem
By default, WordPress form plugins (Contact Form 7, Gravity Forms, WPForms, etc.) only store submissions locally or send them via email. Agencies using GHL then need to manually move that data into campaigns — wasting time and introducing errors.
We want a short-circuit integration: as soon as the form is submitted, the data flows straight into Go High Level.
Hooking Into Form Submissions
WordPress is great at letting you hook into existing events. For example, Contact Form 7 fires the wpcf7_mail_sent action whenever a form is successfully submitted.
Here’s a simple listener:
add_action( 'wpcf7_mail_sent', function ( $contact_form ) {
$submission = WPCF7_Submission::get_instance();
if ( ! $submission ) {
return;
}
$data = $submission->get_posted_data();
// Just log for now
error_log( print_r( $data, true ) );
});
That’s enough to prove we can capture form data at the right moment.
Building the GHL Payload
Next, we transform that form submission into something the Go High Level API understands. For example:
$payload = [
'email' => sanitize_email( $data['your-email'] ?? '' ),
'name' => sanitize_text_field( $data['your-name'] ?? '' ),
'phone' => preg_replace( '/\D+/', '', $data['your-phone'] ?? '' ),
];
This cleans the input and prepares it for JSON encoding.
Sending to Go High Level
Now we use WordPress’s built-in HTTP functions (wp_remote_post) to send the payload:
$response = wp_remote_post( 'https://api.gohighlevel.com/v1/leads', [
'headers' => [
'Authorization' => 'Bearer ' . GHL_API_KEY,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode( $payload ),
] );
if ( is_wp_error( $response ) ) {
error_log( 'GHL API error: ' . $response->get_error_message() );
} else {
error_log( 'Lead sent to GHL successfully.' );
}
This pushes the submission straight into GHL’s workflow engine.
Handling Errors Gracefully
Production code needs to handle edge cases. The plugin checks for:
- Missing API key
- Invalid or incomplete form fields
- Network errors when contacting GHL
Example:
if ( empty( GHL_API_KEY ) ) {
wp_die( 'Missing Go High Level API key.' );
}
This prevents silent failures.
Full Example Flow
Putting it together, a working integration looks like this:
add_action( 'wpcf7_mail_sent', function ( $contact_form ) {
$submission = WPCF7_Submission::get_instance();
if ( ! $submission ) {
return;
}
$data = $submission->get_posted_data();
$payload = [
'email' => sanitize_email( $data['your-email'] ?? '' ),
'name' => sanitize_text_field( $data['your-name'] ?? '' ),
];
$response = wp_remote_post( 'https://api.gohighlevel.com/v1/leads', [
'headers' => [
'Authorization' => 'Bearer ' . GHL_API_KEY,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode( $payload ),
] );
if ( is_wp_error( $response ) ) {
error_log( 'GHL API error: ' . $response->get_error_message() );
}
});
This snippet is essentially the core of the plugin.
Extending Beyond Contact Form 7
The same principle works for other form plugins:
- Gravity Forms → use the
gform_after_submissionaction - WPForms → use the
wpforms_process_completeaction - Custom forms → hook into
admin_post_nopriv_*
The pattern is the same: hook → build payload → send to GHL API.
Front-End Example with JavaScript
If you’re working with a headless WordPress setup, a custom React front end, or just want to push data directly from the browser, you can skip the PHP hooks and post straight to the Go High Level API.
Here’s a minimal vanilla JS example:
<form id="leadForm">
<input type="text" name="name" placeholder="Your name" required />
<input type="email" name="email" placeholder="Your email" required />
<button type="submit">Submit</button>
</form>
<script>
document.getElementById('leadForm').addEventListener('submit', async (e) => {
e.preventDefault();
const form = e.target;
const payload = {
name: form.name.value,
email: form.email.value,
};
try {
const response = await fetch('https://api.gohighlevel.com/v1/leads', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
console.log('Lead sent successfully!');
} catch (err) {
console.error('Error sending lead:', err);
}
});
</script>
This example shows how a form submission can go straight to GHL without touching PHP.
⚠️ Security Note
You should never expose your GHL API key directly in client-side code. In production:
- Proxy requests through WordPress (
wp-jsonendpoint). - Or use a lightweight serverless function (e.g. AWS Lambda, Cloudflare Worker, or Netlify function).
That way, your API key stays secure while still letting the front end send leads seamlessly.
Example: Sending Through WordPress REST
Here’s a PHP snippet to define a simple secure REST endpoint in WordPress:
add_action( 'rest_api_init', function () {
register_rest_route( 'ghl/v1', '/lead', [
'methods' => 'POST',
'callback' => function ( $request ) {
$payload = [
'email' => sanitize_email( $request['email'] ?? '' ),
'name' => sanitize_text_field( $request['name'] ?? '' ),
];
$response = wp_remote_post( 'https://api.gohighlevel.com/v1/leads', [
'headers' => [
'Authorization' => 'Bearer ' . GHL_API_KEY,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode( $payload ),
] );
return rest_ensure_response( $response );
},
'permission_callback' => '__return_true',
] );
});
Then your front-end JS can safely call:
fetch('/wp-json/ghl/v1/lead', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice', email: '[email protected]' })
});
Now the API key never leaves the server, and you still get instant lead capture from the browser.
⚡ Takeaway:
Whether you’re in PHP land or running headless JS apps, the same principle applies: capture → payload → push to GHL API.
Wrapping Up
With just a few lines of code, you can short-circuit lead capture — skipping manual steps and letting WordPress + Go High Level work together automatically.
👉 The complete code and setup instructions are available here: GHL Email Integration on GitHub.
⚡ One-liner takeaway for devs:
Hook into WordPress form actions, build a payload, and fire it straight to Go High Level’s API.