Address autocomplete and validation in Contact Form 7
Give the Contact Form 7 fields ids, attach the address widget, and reject addresses that cannot be found when the form is sent.
Contact Form 7 builds plain input fields from form tags, and you can give each field an id right in the tag. That is all the widget needs. Because CF7 sends the form to your own server, you can also check the address there before the email goes out.
The quick route: the Lynbro Danadresse plugin
The free plugin Lynbro Danadresse from wordpress.org adds address autocomplete to WooCommerce, Contact Form 7, Gravity Forms, WPForms, Fluent Forms, Elementor, GiveWP, Forminator and more. It calls the API through your own server, so the key never reaches the browser.
- In WordPress go to Plugins → Add New, search for "Lynbro Danadresse", click Install and Activate.
- Create a key under Keys. Use a normal live key without allowed domains: the plugin calls the API from your own server, and a domain-locked key is refused there because a server call has no
Origin. - Paste the key under Lynbro → Danadresse → Settings. The Status tab runs a test lookup with the key.
- Contact Form 7 has no address field type of its own, so the plugin finds the address field by auto-detect, or you enter the field's CSS selector under Integrations (e.g.
#dk-adressefrom step 2 below).
The plugin fills postcode and city in separate fields only for form plugins with their own address field (WooCommerce, Gravity Forms, WPForms and others), and it checks addresses on the WooCommerce checkout only. If your CF7 form should fill postcode and city, or refuse addresses that do not exist, use your own code as below.
1. Create keys
You need two keys from Keys:
- a live browser key locked to the site's domains under Allowed domains (see Browser keys and allowed domains)
- a server key without a domain lock for the validation in step 4. Put it in the
DANADRESSE_API_KEYenvironment variable on the server
2. The fields in the form
Edit the form under Contact → Contact Forms:
<label>Address [text* adresse id:dk-adresse]</label> <label>Postcode [text* postnr id:dk-postnr]</label> <label>City [text* by id:dk-by]</label>
3. The widget as an mu-plugin
Save the file as wp-content/mu-plugins/danadresse.php:
<?php /** * Plugin Name: Danadresse autocomplete (Contact Form 7) */ if (!defined('ABSPATH')) { exit; } add_action('wp_enqueue_scripts', function () { wp_enqueue_script( 'danadresse-autocomplete', 'https://danadresse.dk/static/js/danadresse-autocomplete-1.0.0.js', [], null, true ); wp_add_inline_script('danadresse-autocomplete', <<<'JS' const API_KEY = "YOUR_BROWSER_KEY"; function streetLine(a) { let line = a.vejnavn + " " + a.husnr; if (a.etage) line += ", " + a.etage + "."; if (a["dør"]) line += " " + a["dør"]; return line; } const input = document.getElementById("dk-adresse"); if (input) { DanadresseAutocomplete.attach(input, { apiKey: API_KEY, onSelect(a) { input.value = streetLine(a); document.getElementById("dk-postnr").value = a.postnr || ""; document.getElementById("dk-by").value = a.postnrnavn || ""; }, }); } JS ); });
CF7 reads the fields directly when the form is sent, so setting value is enough here.
4. Reject addresses that do not exist
Add this at the bottom of the same file (without a new <?php line). It checks street, number and postcode against /datavask/adgangsadresser and shows an error at the field if the result is category C.
<?php add_filter('wpcf7_validate_text*', function ($result, $tag) { if ($tag->name !== 'adresse') { return $result; } $adresse = sanitize_text_field(wp_unslash($_POST['adresse'] ?? '')); $postnr = sanitize_text_field(wp_unslash($_POST['postnr'] ?? '')); $street = trim((string) strtok($adresse, ',')); $res = wp_remote_get( 'https://api.danadresse.dk/datavask/adgangsadresser?' . http_build_query(['betegnelse' => $street . ', ' . $postnr]), ['headers' => ['X-Api-Key' => getenv('DANADRESSE_API_KEY')], 'timeout' => 5] ); if (is_wp_error($res) || wp_remote_retrieve_response_code($res) !== 200) { return $result; // the API did not answer: let the form through } $vask = json_decode(wp_remote_retrieve_body($res), true); if (($vask['kategori'] ?? '') === 'C') { $result->invalidate($tag, 'We could not find the address. Pick it from the list.'); } return $result; }, 20, 2);
Floor and door are not checked, only the building. What A, B and C mean is explained in Address cleansing in checkout.
5. Test
Send the form twice: once with an address from the list (should go through) and once with a made-up address such as "Findesikkevej 999, 9999" (should show the error). 403 origin_not_allowed in the console means the domain is missing from the browser key.
Next steps
- The CF7 recipe. It uses the older
danadresse-widget.js, which drills down from street to house number to unit and can fill separate fields with itsfieldsoption. - Gravity Forms and WPForms
- The plugin on wordpress.org: Lynbro Danadresse
Related guides
Markdown source Spotted an error? Tell us API-reference (Swagger)