11 min read

Denmark's Under-15 Limit Is Set for 1 July 2027. The Age Check Method Is Still Open, So Build for Three Answers.

Denmark put an under-15 social media bill out for consultation on 7 September 2026, with a 1 July 2027 start. It names no age check method. Here is how to build a gate that survives that.

A dashed amber square on the left with three horizontal bars leaving it to the right: a short grey bar, a medium light blue bar that ends in a dashed amber segment, and a long emerald bar.

On 7 September 2026, the Danish government and its partners put a bill out for public consultation. It sets a national age limit of 15 for social media. The planned start is 1 July 2027. That is about eight months away. The minister says the duty sits directly on the tech companies.

The ministry text doesn’t say how a platform should check age. It doesn’t list the covered services, and it doesn’t name a penalty. So you can’t pick a Danish method today. You can build a gate that doesn’t need to know the method yet. This post shows what that gate returns, and what stays a setting.

What we could confirm

We read the ministry press release of 7 September 2026 and a MereMobil report of 8 September. Both are in Danish. We also read two older English pieces, Biometric Update and Internet for Kids, both from April 2026. We haven’t read the bill text.

  • The limit. 15, for social media.
  • The start. 1 July 2027, planned.
  • The stage. Public consultation from 7 September 2026. According to MereMobil, the bill is expected in parliament in early 2027, then a vote.
  • The backers. The government parties, plus V and KF (the Liberal and Conservative parties), according to the ministry.
  • Who carries the duty. The tech companies. MereMobil quotes Digitalisation Minister Christina Egelund on this.
  • The money angle. The ministry estimates that 327 million Danish kroner a year is spent on ads aimed at children aged 8 to 17 on YouTube, TikTok, Instagram, Facebook and Snapchat. These names appear in that estimate only. They are not a list of covered services.
  • The parental route. MereMobil says children from 13 can get access with a parent’s consent. A Conservative spokesperson calls the 13-to-15 route an open challenge.

What we could not confirm

The age check method. Neither September text names one. MereMobil says the technical age check is still to be refined during the consultation. The April pieces say MitID (Denmark’s national digital ID) is the likely base and that a Danish age app tied to the EU age verification blueprint is planned. Treat that as older and unconfirmed.

We also couldn’t confirm the list of covered services, the penalties, the enforcing body, how the 13-year exception works, what happens to existing accounts, or anything about VPNs. Nothing in the two September texts covers these.

Last, we don’t know today’s status. The consultation started on 7 September. We couldn’t find out whether it has closed or whether the bill has been introduced. The April pieces also disagree on whether the plan was already law. As far as we can tell, it wasn’t. Everything from here on is our reading, not Danish law.

Why an open method is a design problem, not a waiting game

Waiting looks safe. It isn’t, for two reasons.

First, the date is fixed even when the method isn’t. If the bill passes in spring 2027, you get a few weeks, not months, between the final text and the start. Greece also has a fixed start date, and we wrote about what that does to the unsure band in the Greece post.

Second, the method will probably be a list, not one choice. A national digital ID, an EU app, a document check and an age estimate can all end up allowed, each with its own error. If your gate was built around one of them, a change in the list means a rebuild. If your gate takes any of them and returns the same answer, a change in the list means a config edit.

We covered the EU app side in our relying party post. The point here is the shape of the answer.

The gate returns three answers and a fourth state

With a limit of 15 and a reported parental route from 13, your gate has to tell four groups apart.

Answer Who Default action What to keep
under13 Known to be younger than 13 Block The method, the date, the evidence class
13to14 Known to be 13 or 14 Block, or ask a parent if you switch the route on The same, plus the parent step if used
15plus Known to be 15 or older Allow The same
unsure An estimate that straddles a line, or a typed age Step up to a stronger check The estimate range and why it wasn’t enough

The second row is the one to watch. The parental route is reported, but nobody has said what counts as consent. So build it as a switch you can turn on, not as a feature you launch now. When the rule appears, you set one value. How to verify the adult is a hard problem on its own. We wrote about it in the Safe for Kids parent post.

The last row matters most for estimates. An estimator that says “about 15” doesn’t know if the user is 14 or 16. Treat that as a question, not an answer. The same idea sits behind the 16 line post. The line is 15 here, but the logic is the same.

The code

Here is the function that applies the table. It takes evidence from any method and returns a band. It has no idea which method produced the evidence, and that is the point.

export type Evidence =
  | { kind: "birthDate"; value: string } // from a document, a wallet or a national eID
  | { kind: "estimate"; low: number; high: number } // age range from an estimator
  | { kind: "declared"; value: string }; // what the user typed

export type Band = "under13" | "13to14" | "15plus" | "unsure";
export type Action = "allow" | "ask_parent" | "block" | "step_up";

function fullYears(birth: string, today: string): number {
  const [by, bm, bd] = birth.split("-").map(Number);
  const [ty, tm, td] = today.split("-").map(Number);
  return ty - by - (tm < bm || (tm === bm && td < bd) ? 1 : 0);
}

// `today` is an ISO date, taken in Europe/Copenhagen, not in UTC.
export function danishBand(e: Evidence, today: string): Band {
  if (e.kind === "declared") return "unsure";
  if (e.kind === "estimate") {
    if (e.low >= 15) return "15plus";
    if (e.high < 13) return "under13";
    if (e.low >= 13 && e.high < 15) return "13to14";
    return "unsure";
  }
  const age = fullYears(e.value, today);
  return age >= 15 ? "15plus" : age >= 13 ? "13to14" : "under13";
}

// The parental route is a setting, because the rule for it is not published.
export function danishAction(band: Band, parentalRoute: "on" | "off"): Action {
  switch (band) {
    case "15plus": return "allow";
    case "under13": return "block";
    case "13to14": return parentalRoute === "on" ? "ask_parent" : "block";
    case "unsure": return "step_up";
  }
}

We assumed the limit applies on the 15th birthday. Norway plans a calendar-year rule instead, and we wrote about that in the Norway post. Denmark’s text doesn’t say. If the rule turns out to be a year cutoff, fullYears is the only function you change.

These are the tests. We ran them: 7 tests, all passing.

import assert from "node:assert/strict";
import { test } from "node:test";

test("a child who turns 13 tomorrow is under 13 today", () => {
  assert.equal(danishBand({ kind: "birthDate", value: "2013-11-03" }, "2026-11-02"), "under13");
});
test("start date: born 1 July 2012 turns 15 on 1 July 2027, born 2 July 2012 does not", () => {
  assert.equal(danishBand({ kind: "birthDate", value: "2012-07-01" }, "2027-07-01"), "15plus");
  assert.equal(danishBand({ kind: "birthDate", value: "2012-07-02" }, "2027-07-01"), "13to14");
});
test("an estimate that straddles 15 is unsure", () => {
  assert.equal(danishBand({ kind: "estimate", low: 14, high: 16.5 }, "2026-11-02"), "unsure");
  assert.equal(danishBand({ kind: "estimate", low: 15.5, high: 18 }, "2026-11-02"), "15plus");
});
test("a typed age is never an answer", () => {
  assert.equal(danishBand({ kind: "declared", value: "2000-01-01" }, "2026-11-02"), "unsure");
});
test("the parental route is off until you turn it on", () => {
  assert.equal(danishAction("13to14", "off"), "block");
  assert.equal(danishAction("13to14", "on"), "ask_parent");
});

The declared case is deliberate. A typed birth date is a record of what the user said. It is not a check. We made the same point after the Reddit fine, and it applies here too, because “date of birth” fields are still the most common gate on the web.

What to store, so a method change costs nothing

Each decision should record four things: the band, the evidence class (birthDate, estimate or declared), the method name as a free string, and the date. Don’t store the birth date itself if the band is all you need. With these four, a change in the allowed methods is a query: “show me every account whose band came from a method that is no longer on the list.” Without them, it is a re-check of everyone.

This is also your answer to a regulator. A record that says “we used method X on this date and got band Y” is a decision record. A flag that says is_over_15 = true is not.

Accounts you already have

The ministry texts don’t say what happens to existing accounts. Plan for the worst case: every Danish account without a recorded band gets checked, and underage ones are closed. That is a back-book problem, and we described the steps, including appeals, in the back-book post.

The order we would use: new sign-ups first, because that is where the bill will bite first. Then accounts that post, message or buy. Then idle accounts, which you can ask for a check at next login. Don’t close anything on an estimate alone. An estimate is a reason to ask for more, not a reason to delete.

The ad money is part of the picture

The ministry used the 327 million kroner ad figure in its argument. That tells you where political attention is. A platform that has no age band for a user in Denmark will find it hard to explain why that user saw targeted ads. We covered the ad side in the targeted ads post. Expect the age band and the ad profile to be read together.

What it might cost

This is an example, not data from any platform. Say a service has 200,000 Danish accounts. Say 92% can be placed with a browser Check, and 8% (16,000 accounts) land in the unsure band and need a document Verification.

On a paid plan, a Check costs €0.01 to €0.03, and a Verification costs €0.10 to €0.30. So 184,000 Checks cost €1,840 to €5,520. And 16,000 Verifications cost €1,600 to €4,800. The one-time total is €3,440 to €10,320. The 8% is an assumption. If your unsure band is 20%, the Verification line is 2.5 times larger. The size of the band depends mostly on how many users you hold only an estimate or a typed age for.

Checklist for this week

  1. Count your Danish accounts by evidence class: document, wallet or eID, estimate, typed age, nothing.
  2. Add band, evidenceClass, method and decidedAt to the check result record.
  3. Put the parental route behind a setting, default off, and write down who would own turning it on.
  4. Write the unsure path: which stronger check, how long the user waits, and what they can do while they wait.
  5. Decide what a Danish new sign-up sees between now and July if no rule is final. We would block the 13-to-14 band and keep the rest open.
  6. Find out whether your consultation response is still possible. We don’t know if the window is open. If you have a view on methods, the ministry is the place to say it.
  7. Set a date in January to read the bill when it is introduced. The method, the services list and the penalties are the three lines to read first.

The short version

Denmark has fixed the age (15) and the start (1 July 2027), and it has left the method open. That is an advantage if your gate returns bands and records its evidence, and a rebuild if it returns a yes or a no tied to one provider. Build for three answers and a fourth state called unsure. Keep the parental route a switch. Everything else on the list is a setting that the final text will fill in.


Xident provides age verification and age estimation with a decision record on every check. A browser Check is the lower-cost first step, and a document Verification is for users who need a stronger answer. On paid plans a Check costs from €0.01 to €0.03, and a document Verification costs from €0.10 to €0.30. We don’t know yet which method Denmark will accept, and we make no claim about it. Talk to us about the step-up path behind your gate, or see pricing.

Share this article

Ready to implement age verification?

Get started in minutes with our simple SDK. Free trial includes 100 verifications.

Book a 20-minute demo