How to Import Contact Form 7 Entries into Gravity Forms

If you have landed here you are probably mid-migration: the site is moving from Contact Form 7 to Gravity Forms, the new forms are built, and you want the old submissions in the new Entries screen. First, an uncomfortable fact that trips up almost everyone searching for this: Contact Form 7 does not store entries at all by default. It builds an email, hands it to WordPress, and forgets the submission happened. There is no wp_cf7_entries table waiting to be dumped.
So the real question is not “how do I import CF7 entries into Gravity Forms” — it is “where, if anywhere, did my submissions get stored?” Answer that and the rest is mechanical. There is a longer explanation in does Contact Form 7 store data?, but the short version above decides everything that follows.
Step 1: diagnose which situation you are actually in
There are three realistic scenarios. Check them in this order, because the first one you match is the one you work with.
Scenario A — you had Flamingo installed
Flamingo is the companion plugin from CF7’s own author. If it was active, your submissions are sitting in WordPress as a custom post type called flamingo_inbound, with each field stored in post meta prefixed _field_. Look in the admin sidebar for Flamingo → Inbound Messages. If you see rows there, you have data and a clean path forward.
One caveat: Flamingo only captured submissions made while it was active. If you installed it in March, nothing from February exists. Check the oldest message date before promising anyone a complete history.
Scenario B — you used a CF7 database add-on
Plugins like Contact Form CFDB7 write to their own table — typically wp_db7_forms — storing the whole submission as one serialized PHP blob. Recoverable, but the export step means unserializing before you get anything CSV-shaped.
Scenario C — you have nothing but email
No Flamingo, no add-on. In that case there is no database to export from and no honest way to reconstruct a complete entry set. We would rather say that plainly than sell you a workflow that quietly loses half your data.
What you can salvage: export the mailbox folder that received the notifications (most clients export .mbox or .eml; Gmail does it via Google Takeout). CF7 notifications follow a fixed template, so if it never changed you can parse them with reasonable accuracy. It falls apart on multi-line message fields, forwarded threads, and notifications that bounced or were spam-filtered. Treat the result as an archive for reference, not a faithful entry table.
Step 2: get the old entries out to CSV
From Flamingo. Select the messages on the Inbound Messages screen and choose Export: you get one row per submission. It is basic — it exports what it stored, in the column order it likes — but it is trustworthy. For finer control over columns or date formatting, our walkthrough of exporting Contact Form 7 entries to CSV covers the options.
From a database add-on. CFDB7 ships its own per-form export button, which is the easiest route. If it chokes on a large table, query the table directly — but remember the serialized column. A small WP-CLI script that runs maybe_unserialize() over each row and writes fputcsv() output beats a generic phpMyAdmin export, which will hand you raw a:7:{s:4:"name"...} strings.
Whatever the source, open the CSV in a text editor before you go further. You are checking for three things: a consistent column count on every row, dates in one format rather than three, and no stray line breaks inside message fields that have broken the row structure.
Step 3: import into Gravity Forms
Here is the second uncomfortable fact: Gravity Forms has no native CSV entry importer. It exports entries beautifully and imports nothing. So you pick one of three routes.
| Route | Good for | Pros | Cons |
|---|---|---|---|
Gravity Forms CLI add-on (wp gf entry create) |
Anyone comfortable on the command line | Official, free with your licence, scriptable, no extra plugin on the front end, easy to re-run after a bad batch | Requires WP-CLI and SSH; you write the loop that reads the CSV yourself |
| Third-party entry-import add-on | Non-technical site owners, one-off migrations | Point-and-click column mapping, previews before committing, handles the entry meta for you | Usually paid; mapping UIs vary in quality; another plugin to maintain or remove afterwards |
Custom script using GFAPI::add_entry() |
Messy or unusual source data | Total control over parsing, transformation and field IDs; can set the original date directly | You own the bugs; needs a real staging environment and care with large batches |
All three ultimately do the same thing: build an entry array keyed by Gravity Forms field IDs and hand it to the API. Which brings us to the part that actually costs people time.
Field mapping: where migrations go wrong
Gravity Forms does not identify fields by name. It identifies them by numeric ID, and complex fields use decimal sub-IDs. Open your form, note the ID of each field (the editor shows it, or check the URL when editing a field), and write the mapping down before you touch any code.
- Names and addresses. A Name field is not
4— it is4.3for first and4.6for last, and an Address spreads across5.1to5.6. If CF7 had a single “your-name” input, decide whether to split it or map it to a plain text field; naive splitting on the first space mangles compound surnames. - Checkboxes and multi-selects. CF7 stored these as a comma-separated string. Gravity Forms wants one array key per choice (
7.1,7.2,7.3), and the value must match the choice value exactly, not the label. Mismatches import silently as blanks. - Dates. Gravity Forms stores dates as
Y-m-dwhatever display format you picked. Normalise every date column first, and watch ford/m/Yversusm/d/Yambiguity. - File uploads. Gravity Forms stores a URL, not the file. Copy the physical files from the CF7 upload folder into the Gravity Forms uploads directory first, then import the resulting URLs — otherwise you get a tidy table of dead links.
- Empty fields. Omit them rather than importing empty strings; it keeps the entry list and conditional exports cleaner.
Preserve the original submission date
By default every imported entry gets today’s date, destroying the one piece of context that made the archive worth keeping. Set date_created explicitly, as Y-m-d H:i:s in UTC — Gravity Forms stores UTC and converts for display, so local time shifts every entry by your timezone offset. Convert first, then spot-check a few entries in the admin against the original CSV.
Test on staging first — genuinely
Entry imports are not reversible. There is no “undo import”; cleaning up a bad run means deleting entries by ID or restoring a backup. Run it on a staging copy, import ten rows before ten thousand, and check those ten in the admin UI — not just the database. Then back up production and repeat.
Also decide whether notifications should fire. They should not. Both the CLI and GFAPI::add_entry() skip notifications by default, but disable any custom entry-creation hooks for the duration — emailing three years of old contacts a “thanks for your submission” is a memorable way to end a migration. The same principles apply to any form-to-form move; we collected them in our guide to migrating form entries between plugins.
The real lesson: don’t end up here again
Every painful version of this migration has the same root cause — the form plugin was never storing submissions, and nobody noticed until the data was needed. Gravity Forms does store entries, so switching fixes it going forward. But if you run several form plugins across several sites, it helps to have storage that does not depend on which builder you happen to use this year.
Full disclosure: our own free plugin, EntryVault, captures and stores entries from 11 form builders including both Contact Form 7 and Gravity Forms, keeping every submission in one place regardless of which plugin produced it. It will not recover submissions you never saved — nothing will — but it means the next migration is an export, not an archaeology project.
Frequently asked questions
Can I import Contact Form 7 entries into Gravity Forms if I never installed Flamingo?
Not from the database, because Contact Form 7 never stored them. Your only source is the notification emails that were sent at the time. You can export that mailbox and parse the messages into a CSV, but the result will be incomplete — bounced or spam-filtered notifications, changed email templates and multi-line message fields all cause gaps. Treat it as a partial archive rather than a true entry history.
Does Gravity Forms have a built-in CSV entry importer?
No. Gravity Forms can export entries to CSV but cannot import them natively. The three practical routes are the official Gravity Forms CLI add-on, a third-party entry-import add-on, or a custom script calling GFAPI::add_entry(). All three require you to map your CSV columns onto Gravity Forms numeric field IDs.
How do I keep the original submission dates instead of the import date?
Set the date_created value explicitly on each entry, formatted as Y-m-d H:i:s in UTC. Gravity Forms stores dates in UTC and converts them for display, so if your source data uses local time you must convert it first, or every entry will be offset by your timezone. Verify a few imported entries against the original CSV before running the full batch.