How it works
- A new field,
billing_cvr, is added to checkout below the company name. - Once the customer has typed 8 digits, a small script calls
https://apicvr.dk/api/v1/{cvr}. - Company name, address, postcode and city are filled in automatically.
- Optional: the CVR number is validated on the server before the order is created.
1. Add the CVR field and the script
Put this in your child theme's functions.php or in a small plugin. WooCommerce automatically saves the field on the order as the meta key _billing_cvr.
<?php
// functions.php in your (child) theme, or a small plugin
add_filter( 'woocommerce_checkout_fields', function ( $fields ) {
$fields['billing']['billing_cvr'] = array(
'type' => 'text',
'label' => 'CVR number',
'required' => false,
'class' => array( 'form-row-wide' ),
'priority' => 25, // right after company name
'maxlength' => 8,
);
return $fields;
} );
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_checkout() ) {
return;
}
wp_enqueue_script(
'cvr-autofill',
get_stylesheet_directory_uri() . '/cvr-autofill.js',
array(),
'1.0',
true
);
} );
2. Autofill with JavaScript
Save this as cvr-autofill.js in your child theme. The API sends Access-Control-Allow-Origin: *, so the request can run straight from the browser with no proxy and no API key.
// cvr-autofill.js
document.addEventListener('DOMContentLoaded', () => {
const cvrInput = document.getElementById('billing_cvr');
if (!cvrInput) return;
const setField = (id, value) => {
const el = document.getElementById(id);
if (!el || value === null || value === undefined) return;
el.value = value;
el.dispatchEvent(new Event('change', { bubbles: true }));
};
cvrInput.addEventListener('input', async () => {
const cvr = cvrInput.value.replace(/\D/g, '');
if (cvr.length !== 8) return;
try {
const res = await fetch(`https://apicvr.dk/api/v1/${cvr}`);
if (!res.ok) return; // 404 = unknown CVR number
const company = await res.json();
setField('billing_company', company.name);
setField('billing_address_1', company.address);
setField('billing_postcode', company.zipcode);
setField('billing_city', company.city);
} catch (err) {
// Network error: let the customer fill in the fields by hand.
}
});
});
3. Validate the CVR number on the server (optional)
The browser can be bypassed, so validate on the server too. A 404 from the API means the CVR number doesn't exist. If the API is unreachable, the order goes through anyway so you don't lose the sale.
<?php
add_action( 'woocommerce_checkout_process', function () {
$cvr = isset( $_POST['billing_cvr'] )
? preg_replace( '/\D/', '', wp_unslash( $_POST['billing_cvr'] ) )
: '';
if ( '' === $cvr ) {
return; // the field is optional
}
if ( 8 !== strlen( $cvr ) ) {
wc_add_notice( 'The CVR number must be 8 digits.', 'error' );
return;
}
$response = wp_remote_get( 'https://apicvr.dk/api/v1/' . $cvr, array( 'timeout' => 10 ) );
if ( is_wp_error( $response ) ) {
return; // don't block checkout if the API is unreachable
}
if ( 404 === wp_remote_retrieve_response_code( $response ) ) {
wc_add_notice( 'We could not find that CVR number in the CVR register.', 'error' );
}
} );
[woocommerce_checkout]). If your store uses the new block-based checkout, the woocommerce_checkout_fields filter has no effect; add the field with WooCommerce's Additional Checkout Fields API instead.Respect marketing protection
If you store customers' company data for newsletters or other marketing, check the protected field. When it's true, the company has opted out of marketing. Read more about marketing protection.
Frequently asked questions
Do I need a plugin?
No. The code above can live in your child theme's functions.php. If you want it to survive theme changes, wrap it in a small plugin.
Where is the CVR number stored?
WooCommerce saves fields added through woocommerce_checkout_fields as order meta, under the key _billing_cvr.
Do the CVR lookups cost anything?
No. CVR-API is free and needs no API key. Fair-use rate limits apply.