Age, country and who may play
No gameplay token is issued to a player Crowded Kingdoms may not admit. Every mint and every
refresh checks the player, whichever way the token is asked for (mintAppToken,
refreshAppToken, hosted sign-in,
or an organization signing in one of its own players), in
this order:
- Country:
TERRITORY_NOT_SUPPORTEDwhere Crowded Kingdoms does not offer its services. - Age:
AGE_REQUIREDwhen the player's age is not known,AGE_REQUIREMENT_NOT_METwhen the player is younger than the app allows where they are. - Documents:
LEGAL_ACCEPTANCE_REQUIREDuntil the player has accepted the platform's documents and the app's own (Legal documents).
A sign-up checks the country and the age before the account exists.
- Since 2026-11-04, when Crowded Kingdoms opened to players 13 and over: the youngest player is 13; a browser sign-up gives a birth date and a country; an organization gives an age and a country for each player it signs in; developers are adults.
- Game API v2.60.0: the checks above; the birth date and country at sign-up and in
recordPlayerAge; a managed player'sageYearsandcountry; an app'sminPlayerAge; and the country list, enforced for every player, adults included. - Game API v2.61.0 and v2.61.1: age refusals that name no age, and the lock after one; the
erasure of an account that declares an age under 13; countries checked by region, and a managed
player's
region; Crowded Kingdoms staff past the country check.
What changed on 2026-11-04
| Before | Since | |
|---|---|---|
| Youngest player | 18 | 13, or older where the app or the player's country asks |
| How a Crowded Kingdoms account's age is known | the age-of-majority attestation, or a birth date | the birth date; the attestation is ignored |
| A birth date at a browser sign-up | optional | required |
A managed player's ageYears and country | optional: with no age, the player counted as 18 or older, as the organization warranted | required |
| Countries Crowded Kingdoms does not serve | refused | refused |
An account that attested its age before 2026-11-04 keeps the bracket 18_plus and is not asked
again.
Ages are kept as brackets
A player's age is one of five brackets: unknown (not given yet), under_13, 13_15, 16_17
and 18_plus. Of a birth date only the year and month are kept, and the age is counted from the
last day of that month, so it is never overstated; the bracket moves on that day. A player reads
their own:
query { me { ageBracket country } }
Both are private: null to anyone but the player. Your app's server code reads a player's bracket,
never their age, with players.get.
Signing up
register takes three more fields in registerUserInput:
| Field | What |
|---|---|
birthDate | YYYY-MM-DD, or YYYY-MM |
country | where the player lives, ISO 3166-1 alpha-2, such as US; sent with birthDate |
parentalConfirmation | true when a player under 18 confirms that a parent or guardian agreed; required under 18, ignored at 18 and over |
mutation SignUp($input: RegisterUserInput!) {
register(registerUserInput: $input) { token user { userId } }
}
# variables: { "input": { "email": "...", "password": "...", "acceptLegal": true,
# "birthDate": "1994-04", "country": "US" } }
attestAgeOfMajority is ignored since 2026-11-04. Before any account exists, the sign-up is
refused:
TERRITORY_NOT_SUPPORTEDfor a place Crowded Kingdoms does not serve: the country the player gave, or the country or region their connection comes from;AGE_REQUIREMENT_NOT_METunder 13, or under the country's minimum. It names no age, and the same client is then refusedAGE_REQUIREMENT_NOT_METhere and atrecordPlayerAge, whatever it sends (the retry lock);BAD_REQUESTfor a date that is not a real date in the past, a country without a birth date or a birth date without one, or a player under 18 withoutparentalConfirmation: true.
A browser sign-up without a birth date is refused AGE_REQUIRED. A request with no Origin
header (a native client, a tool) may leave the three fields out and give them with
recordPlayerAge before its first mint.
An account with no age: recordPlayerAge
An account whose ageBracket is unknown gives its birth date, country and (under 18) the
parent's agreement once, with its session token:
mutation {
recordPlayerAge(input: { birthDate: "1994-04-17", country: "US" }) { ageBracket country }
}
A player under 18 sends parentalConfirmation: true as well. The answer cannot be changed by
asking again, so record what the player entered, never a test value, on an account that will
play.
- An account that already has an age is refused
CONFLICT, an attested one included: the age is not changed here. A Crowded Kingdoms operator corrects a wrong one. - A place Crowded Kingdoms does not serve is refused
TERRITORY_NOT_SUPPORTED, except for Crowded Kingdoms staff. - Under 13 is refused
AGE_REQUIREMENT_NOT_MET, and the account is deleted and erased, asdeleteMyAccountdoes (Game API v2.61.0): Crowded Kingdoms keeps no personal information about the child. The same client is then locked out, as after a sign-up. - Whether the player may play a given app (its minimum age, the country's) is decided at the mint, not here.
The age screen
Any screen that asks a player's age for Crowded Kingdoms follows these rules: a sign-up form, a launcher, an in-game prompt, or the screen of a server that signs its own players in.
-
Ask for the date of birth and the country. A month and a year is enough. Pick neither for the player, and suggest no answer.
-
Show no age. Not the youngest age allowed, and not the player's age.
-
Show the parental line only to a player whose date makes them 13 to 17, worded with no age. With it the player confirms that a parent or guardian agreed to the terms for them; send it as
parentalConfirmation: true. -
A refusal names no age. Tell the player they cannot sign up or play, without a reason, an age or a way to try again.
AGE_REQUIREMENT_NOT_METcarries no extensions and its message names no age (Game API v2.61.0), so there is nothing in it to show. -
Do not offer an immediate retry after an age refusal: no way back to the date to change it. Crowded Kingdoms stops one as well, whatever is sent next (Game API v2.61.1):
- at sign-up and
recordPlayerAge, a client that sends anx-ck-device-idheader (an opaque random id it keeps, 16 to 128 letters, digits,-or_) is refused for 24 hours by that device, wherever it connects from; one that sends none is refused for an hour by its address and user agent, which schools, households and carriers share; - the same Minecraft account, for 24 hours;
- the same managed player (your organization and its
externalId), for 24 hours, in any of the organization's apps.
That stops an immediate retry; it is not a barrier, so your screen keeps its own lockout. Send
x-ck-device-idfrom a native client to get the day-long lock. - at sign-up and
Minimum ages
The youngest player an app admits is the highest of three:
- the platform's: 13 (18 before 2026-11-04);
- the app's,
minPlayerAge, from 13 to 18, which only ever raises the platform's; - the country's, from
territoryPolicies.
mutation AdultsOnly($appId: BigInt!) {
updateApp(appId: $appId, input: { minPlayerAge: 18 }) { minPlayerAge effectiveMinPlayerAge }
}
App.effectiveMinPlayerAge is the higher of the app's and the platform's. minPlayerAge: null
returns the app to the platform's minimum. A raised minimum applies at each player's next mint or
refresh: a younger player is refused AGE_REQUIREMENT_NOT_MET. An app whose minimum is 18 admits
no minor, and needs no safety log: set it to keep
a game for adults.
Countries
query { territoryPolicies { countryCode regionCode status minAge } }
territoryPolicies is public, so a sign-up form can say so before an account exists. It lists the
countries Crowded Kingdoms does not serve (status: "blocked") and those whose minimum age is
above 13, then the regions it lists (regionCode, ISO 3166-2). A country it does not list is open
at the platform's minimum. Read it rather than keeping a copy: the list changes, and every server
applies a change within a minute, refusing a player already signed in there at their next refresh.
- A Crowded Kingdoms account is checked on the country the player gave, and the country and region their connection comes from; any one blocked refuses. Hosted sign-in checks the player's browser when Studio issues the code, and not again when your game exchanges it.
- Countries checked by region (Game API v2.61.0): a country with a region listed is checked by region. A connection from it whose region cannot be told is refused; Crowded Kingdoms asks a second location database before it does. The country a player gives is checked by country only, since sign-up asks no region.
- A managed player is checked on the country, and where needed the region, its organization gives.
- For everyone, from Game API v2.60.0, not only for players under 18. Crowded Kingdoms
staff pass the country check at the mint and at
recordPlayerAge(Game API v2.61.0), and are checked at sign-up like anyone, since an account's staff role is not known before it exists. The age checks apply to them as to everyone. - The refusal carries
extensions.country, andextensions.regionwhen a region decided it (null otherwise).
The Player Terms say where Crowded Kingdoms
offers its services (section 1.7) and the minimum age by country (section 1.8);
territoryPolicies is what the API enforces.
Players your organization signs in
A managed player has no Crowded Kingdoms sign-up, so your organization gives its age and country
at every sign-in: ageYears (whole years) and country (ISO 3166-1 alpha-2) on
mintManagedPlayerToken, or as the ageYears and country claims of a signed assertion. In a
country checked by region, it gives region too (ISO 3166-2, such as UA-30), which is checked
at each sign-in and not stored (Game API v2.61.0).
- Under 13, or under the app's or the country's minimum, the player is refused
AGE_REQUIREMENT_NOT_METbefore it is created or signed in, and the same player (your organization and itsexternalId) is refused again for 24 hours, in any of your organization's apps, whatever age you send. A player that already exists and is now said to be under 13 is deleted, asdeleteManagedPlayerdoes. - A place Crowded Kingdoms does not serve, or a missing
regionwhere one is needed, is refusedTERRITORY_NOT_SUPPORTED. - The bracket and the country are stored on the player. A refresh, which carries no age, is refused once the stored bracket is wholly below the app's minimum.
- Both are required: no age is
AGE_REQUIRED, no countryBAD_REQUEST. (Before 2026-11-04 both were optional, and a player with no age counted as 18 or older.) - A player under 18 gets the minors' defaults: voice and video off
until a parent consents, then contacts only, and no direct messages. The app must keep its
safety log on (
SAFETY_LOG_REQUIREDotherwise), and your organization must have appointed a moderator (SAFETY_MODERATOR_REQUIREDotherwise).
If your server asks players their age, the age screen applies to it. See Org-managed players.
Developers
Creating an organization and administering one or its apps need the developer
documents (Legal documents), which only adults may accept:
an account with no age is refused AGE_REQUIRED (recordPlayerAge first), and one under 18
AGE_REQUIREMENT_NOT_MET. A player of 13 to 17 plays, and does not build on Crowded Kingdoms.
In the SDKs
| CrowdyJS 18.25.0 | CrowdyCPP 0.76.0 | CrowdyPy 0.24.0 | |
|---|---|---|---|
| Sign-up with the age | auth.register({ …, birthDate, country, parentalConfirmation }) | auth().registerUser(RegisterUserInput) | auth.register(…, birth_date=, country=, parental_confirmation=) |
| An account with no age | auth.recordPlayerAge({ birthDate, country, parentalConfirmation }) | auth().recordPlayerAge(PlayerAgeInput) | auth.record_player_age(birth_date=, country=, parental_confirmation=) |
| The bracket and country | users.me() | users().me() | users.me() |
The country and region list (regionCode) | platform.territoryPolicies() | platform().territoryPolicies() | platform.territory_policies() |
| The refusals | territoryNotSupportedOf, ageRequiredOf, ageRequirementNotMetOf, safetyLogRequiredOf, safetyModeratorRequiredOf | graphql::territoryNotSupportedOf and the same names | territory_not_supported_of and the same names, in crowdypy.errors |
The age readers surface no age. None of the SDKs wraps mintManagedPlayerToken, which runs on
your organization's server; CrowdyJS and CrowdyPy type the assertion's claims
(ManagedPlayerAssertionClaims: ageYears, country, region).
Refusals
extensions.code | HTTP | When | What to do |
|---|---|---|---|
TERRITORY_NOT_SUPPORTED | 403 | The player's place, the country they gave or their connection's country or region (extensions.country, extensions.region), is one Crowded Kingdoms does not serve; or, in a country checked by region, the region cannot be told or a managed player was sent without one. | Tell the player Crowded Kingdoms is not available where they are. Do not retry. |
AGE_REQUIRED | 403 | The player's age is not known: an account with no age, a browser sign-up without birthDate, or a managed player signed in without ageYears. | Ask the age (the age screen), then recordPlayerAge, or sign the managed player in with ageYears and country. |
AGE_REQUIREMENT_NOT_MET | 403 | The player is younger than the app allows where they are, or under 13; or a developer under 18; or the same device, client, Minecraft account or managed player was refused so recently (the retry lock). No extensions. | Tell the player they cannot play this, without a reason, an age or a way to try again. Do not retry with another date or age. |
LEGAL_ACCEPTANCE_REQUIRED | 403 | Documents are missing (extensions.missingDocuments). | Legal documents. |
SAFETY_LOG_REQUIRED | 403 | A player under 18, in an app whose safety log is off: at the mint, and since Game API v2.61.1 when Studio's hosted sign-in issues the code. | The app's admins turn it on (the safety log). Tell the player the game cannot admit them yet. |
SAFETY_MODERATOR_REQUIRED | 403 | A player under 18, in an app whose organization has no appointed moderator (Game API v2.61.0; at the hosted sign-in's code too since v2.61.1). | The organization gives a member a role that grants moderate_safety (Moderators). Tell the player the game cannot admit them yet, naming no age. |
CONFLICT | 409 | recordPlayerAge on an account that has an age. | Read me { ageBracket }; do not ask again. |
BAD_REQUEST | 400 | A malformed date or country, one without the other, or a player under 18 without parentalConfirmation. | Fix the input. |
All codes are on Error codes.