Contact Form 7 → Google Sheets (via Apps Script)

1. Create Google Sheet

  1. In Google Drive, create a new sheet:
    ClientName - Leads
  2. Add a tab named Leads with headers: Timestamp | Name | Email | Phone | Message | CF7_Form_ID
  3. Copy the Sheet ID from the URL: https://docs.google.com/spreadsheets/d/THIS_IS_THE_SHEET_ID/edit

2. Apps Script (Webhook)

  1. Open the sheet → Extensions → Apps Script.
  2. Paste the following code:
// Apps Script: CF7 -> Google Sheet webhook
const SHARED_SECRET = 'REPLACE_WITH_RANDOM_SECRET';
const SHEET_ID = 'REPLACE_WITH_SHEET_ID';

function doPost(e) {
  try {
    var payload = {};
    if (e.postData && e.postData.type === 'application/json') {
      payload = JSON.parse(e.postData.contents || '{}');
    } else if (e.parameter && Object.keys(e.parameter).length) {
      payload = e.parameter;
    } else {
      payload = { raw: e.postData && e.postData.contents ? e.postData.contents : '' };
    }

    if (!payload.token || payload.token !== SHARED_SECRET) {
      return ContentService.createTextOutput(JSON.stringify({ status: 'error', message: 'unauthorized' }))
                           .setMimeType(ContentService.MimeType.JSON);
    }

    var ss = SpreadsheetApp.openById(SHEET_ID);
    var sheet = ss.getSheetByName('Leads') || ss.getSheets()[0];

    var row = [
      new Date(),
      payload['your-name'] || '',
      payload['your-email'] || '',
      payload['your-phone'] || '',
      payload['your-message'] || '',
      payload['_cf7_form_id'] || ''
    ];

    sheet.appendRow(row);

    return ContentService.createTextOutput(JSON.stringify({ status: 'ok' }))
                         .setMimeType(ContentService.MimeType.JSON);
  } catch (err) {
    return ContentService.createTextOutput(JSON.stringify({ status: 'error', message: err.toString() }))
                         .setMimeType(ContentService.MimeType.JSON);
  }
}
  1. Save → Deploy → New deployment → Web app.
    • Execute as: Me
    • Who has access: Anyone with link
  2. Copy the /exec URL.

3. Contact Form 7 (Hidden Fields)

In the Form tab of your CF7 form, add:

[hidden token "REPLACE_WITH_RANDOM_SECRET"]

4. WordPress PHP (functions.php or Code Snippets)

Add this code to your theme’s functions.php or a snippets plugin.
Replace the token and Apps Script URL with your own values.

<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

add_action( 'wpcf7_mail_sent', 'cf7_send_to_google_sheet' );

function cf7_send_to_google_sheet( $contact_form ) {
    $submission = WPCF7_Submission::get_instance();
    if ( ! $submission ) {
        return;
    }

    $posted = $submission->get_posted_data();

    $payload = array(
        'token'        => 'REPLACE_WITH_RANDOM_SECRET',
        'your-name'    => isset( $posted['your-name'] ) ? (string) $posted['your-name'] : '',
        'your-email'   => isset( $posted['your-email'] ) ? (string) $posted['your-email'] : '',
        'your-phone'   => isset( $posted['your-phone'] ) ? (string) $posted['your-phone'] : '',
        'your-message' => isset( $posted['your-message'] ) ? (string) $posted['your-message'] : '',
        '_cf7_form_id' => $contact_form->id()
    );

    $url = 'https://script.google.com/macros/s/YOUR_DEPLOYED_EXEC_ID/exec';

    $args = array(
        'body'      => $payload,
        'timeout'   => 20,
        'blocking'  => true,
        'headers'   => array( 'Content-Type' => 'application/x-www-form-urlencoded' )
    );

    $response = wp_remote_post( $url, $args );

    if ( is_wp_error( $response ) ) {
        error_log( 'CF7->Sheet error: ' . $response->get_error_message() );
    } else {
        error_log( 'CF7->Sheet response: ' . wp_remote_retrieve_body( $response ) );
    }
}

5. Test

  1. Submit the CF7 form with test values.
  2. Open the Google Sheet → confirm a new row was added.
  3. Check WordPress debug.log or Apps Script → Executions for errors if needed.

6. Limits (Google Quotas)

  • Writes per day (Apps Script): ~20,000 rows.
  • Sheet size: 10M cells (~1M rows with 10 columns).
  • Request size: ~50 MB (CF7 data is tiny).
  • Execution time: 6 mins/request (your script runs <1s).

7. Best Practices

  • Keep Google Sheet private (do not share as “Anyone with link”).
  • Keep Apps Script deployment as “Anyone with link” but protect with token check.
  • Use strong random secret tokens (rotate if leaked).
  • Enable reCAPTCHA in CF7 to reduce spam.
  • Archive leads when sheet grows large (>50k rows).

👉 This snippet is generic — safe to store in your docs and reuse for any future project.