Open Hive Data Standard
A universal interchange format for beekeeping citizen science data. One privacy-first export format that maps cleanly to BIP, COLOSS, HoneyBeeNet, and any future program.
OHDS is a domain specialization of VODS (Veydrin Open Data Standard). Every OHDS document is also a valid VODS document. OHDS adds the ohds_version field and the domain payload — inspections and apiary_summary arrays — on top of the VODS envelope. Refer to the VODS v1.0 specification for the full definition of envelope fields, the anonymization model, the extensions system, and the versioning contract. This document specifies only what OHDS adds.
vods_version, export_id, export_date, export_mode) are required in every OHDS document by virtue of the VODS dependency. They are described here for reference; their authoritative definition is in the VODS spec.
An OHDS file is a single .ohds.json file. Applications export it; converters transform it into program-specific formats. No SDK or library is required. Any developer who can write JSON can implement the standard in an afternoon.
Every OHDS document begins with the VODS envelope (inherited) followed by the OHDS domain version field. Together these five fields identify the document and its conformance claims.
| Field | Type | Source | Req? | Description |
|---|---|---|---|---|
vods_version | string | VODS | req | VODS version this document conforms to. Must be "1.0" for documents conforming to VODS v1.0. |
export_id | string (UUID) | VODS | req | Random UUID v4, generated fresh per export. Never reused. |
export_date | string (ISO 8601) | VODS | req | Full datetime with timezone. Example: "2026-03-09T14:22:00Z". |
export_mode | enum | VODS | req | "anonymous" — randomized refs per export. "tracked" — stable per-program pseudonymous refs. See VODS §3. |
ohds_version | string | OHDS | req | OHDS specification version. Currently "1.0". Consumers must accept any version with a matching major number. |
extensions | object | VODS | opt | Namespaced org-specific fields. Consumers ignore unrecognized namespaces. See VODS §4. |
An OHDS document must contain at least one of inspections or apiary_summary, and whichever arrays are present must be non-empty. A document with neither array, or with both arrays empty, is not valid OHDS.
One record per hive visit. The inspections array contains these records. Fields marked optional may be omitted entirely — do not include a field with a null value.
| Field | Type | Req? | Description |
|---|---|---|---|
inspection_date | string (ISO 8601 date) | req | Date of inspection. "2026-03-01". |
apiary_ref | string | req | Pseudonymous apiary identifier. Groups hives by apiary. Links to apiary_summary records. |
hive_ref | string | req | Pseudonymous hive identifier. Generated per the active export_mode. Never the internal database ID. |
colony_status | enum | req | alive · dead · absconded · lost_queen · split · merged |
hive_type | enum | opt | langstroth · top_bar · warre · flow · long · skep · other |
bee_race | enum | opt | italian · carniolan · russian · buckfast · caucasian · local_mutt · africanized · unknown · other |
brood_pattern | enum | opt | solid · spotty · none |
queen_seen | boolean | opt | Whether the queen was directly observed. |
queen_status | enum | opt | present · missing · replaced · supercedure · unknown |
frames_of_bees | number | opt | Estimated population in standard frames of bees. |
frames_of_brood | number | opt | Number of frames containing brood. |
frames_of_honey | number | opt | Number of frames of capped honey stores. |
varroa_count | number | opt | Mite count per 100 bees (or per the method below). |
varroa_method | enum | opt | alcohol_wash · sugar_roll · sticky_board · drone_uncapping |
treatments | array | opt | Treatments applied during or since last inspection. See §3.1. |
feeding | object | opt | Feed provided. See §3.2. |
weight_kg | number | opt | Hive weight in kilograms (scale hives). |
temperature_c | number | opt | Ambient temperature in Celsius at time of inspection. |
weather | enum | opt | sunny · partly_cloudy · overcast · rain · wind |
notes | string | opt | Free-text notes. Omitted in anonymous exports if the app strips notes as a privacy measure. |
coordinates | object | opt | Opt-in only. {"lat": 30.2, "lon": -97.7} WGS 84. Coarsened to ±0.1° minimum in anonymous mode. |
| Field | Type | Req? | Description |
|---|---|---|---|
product | string | req | Product or compound name (e.g., "oxalic acid", "ApiVar"). |
method | enum | req | vaporization · strip · drizzle · drench · dusting · fogger · feed_additive · other |
date_start | string (date) | opt | Treatment start date. |
date_end | string (date) | opt | Treatment end date. |
| Field | Type | Req? | Description |
|---|---|---|---|
type | enum | req | sugar_syrup_1:1 · sugar_syrup_2:1 · dry_sugar · candy · pollen_sub · other |
quantity_kg | number | req | Amount fed in kilograms. |
One record per apiary per season. Used for loss surveys (BIP, COLOSS). The apiary_summary array contains these records.
| Field | Type | Req? | Description |
|---|---|---|---|
apiary_ref | string | req | Pseudonymous apiary identifier. Same value as used in inspection records for this apiary. |
season | enum | req | winter · spring · summer · fall · annual |
year | string | req | Reporting year or range. "2025" or "2025-2026" for winter seasons. |
season_start | string (date) | opt | Start date of the reporting season. Programs define their own boundaries; include when known. |
season_end | string (date) | opt | End date of the reporting season. |
colonies_start | integer | req | Colonies at the start of the season. |
colonies_end | integer | req | Colonies surviving at the end of the season. |
lost_dead | integer | opt | Colonies lost — colony died. |
lost_queen | integer | opt | Colonies lost — queen failure. |
lost_disaster | integer | opt | Colonies lost — external event (weather, vandalism, etc.). |
new_purchased | integer | opt | New colonies acquired by purchase. |
new_splits | integer | opt | New colonies created by split. |
colonies_sold | integer | opt | Colonies sold or given away during the season. |
perceived_loss_causes | string[] | opt | Beekeeper's attributed causes. Suggested values: varroa · nosema · pesticides · starvation · weather · ccd · weak_fall · unknown |
operation_size | enum | opt | backyard (1–24) · sideline (25–299) · commercial (300+) |
migratory | boolean | opt | Whether hives were moved for pollination or honey production. |
region | string | opt | ISO 3166-2 region code. Example: "US-TX", "DE-BY". |
total_lost / colonies_at_risk, where at-risk = colonies_start + new_purchased + new_splits. Include these fields when targeting BIP format.
{
// VODS envelope
"vods_version": "1.0",
"export_id": "a3f8c2e1-04b7-4d9e-b221-7f3a09cc1d82",
"export_date": "2026-03-09T14:22:00Z",
"export_mode": "anonymous",
// OHDS domain fields
"ohds_version": "1.0",
"inspections": [
{
"inspection_date": "2026-03-01",
"apiary_ref": "A-9f4c", // randomized this export
"hive_ref": "H-2a71", // randomized this export
"colony_status": "alive",
"hive_type": "langstroth",
"bee_race": "italian",
"frames_of_bees": 8,
"varroa_count": 1.4,
"varroa_method": "alcohol_wash",
"treatments": [
{
"product": "oxalic acid",
"method": "vaporization",
"date_start": "2026-02-15"
}
]
}
],
"apiary_summary": [
{
"apiary_ref": "A-9f4c",
"season": "winter",
"year": "2025-2026",
"season_start": "2025-10-01",
"season_end": "2026-04-01",
"colonies_start": 12,
"colonies_end": 10,
"lost_dead": 1,
"lost_queen": 1,
"new_splits": 2,
"operation_size": "backyard",
"region": "US-TX"
}
]
}
{
// VODS envelope — tracked mode for longitudinal program
"vods_version": "1.0",
"export_id": "d91cc3f4-88ab-4e02-a301-0f2b17dc5e41",
"export_date": "2026-03-09T14:22:00Z",
"export_mode": "tracked",
"ohds_version": "1.0",
"inspections": [
{
"inspection_date": "2026-03-01",
"apiary_ref": "A-bip-7c3d", // stable for BIP program
"hive_ref": "H-bip-4f19", // stable for BIP program
"colony_status": "alive",
"frames_of_bees": 9,
"varroa_count": 0.8,
"varroa_method": "alcohol_wash"
}
],
"extensions": {
"hfh": {
"program_cohort": "Spring 2026",
"mentor_id": "M-42"
}
}
}
These snippets transform an OHDS document into the format expected by major citizen science programs. They are reference implementations — not the only valid approach.
def ohds_to_bip(ohds: dict) -> list[dict]:
"""Convert OHDS apiary_summary records to BIP loss survey rows."""
rows = []
for s in ohds.get("apiary_summary", []):
start = s["colonies_start"]
purchased = s.get("new_purchased", 0)
splits = s.get("new_splits", 0)
at_risk = start + purchased + splits
lost = start - s["colonies_end"]
rows.append({
"apiary_id": s["apiary_ref"],
"season": s["season"],
"year": s["year"],
"colonies_oct1": start,
"colonies_april": s["colonies_end"],
"total_lost": lost,
"loss_rate": round(lost / at_risk, 4) if at_risk else None,
"operation_size": s.get("operation_size"),
"region": s.get("region"),
})
return rows
def ohds_to_coloss(ohds: dict) -> list[dict]:
"""Convert OHDS apiary_summary to COLOSS questionnaire rows."""
rows = []
for s in ohds.get("apiary_summary", []):
rows.append({
"apiary_ref": s["apiary_ref"],
"country_region": s.get("region", ""),
"season": s.get("season"),
"year": s["year"],
"season_start": s.get("season_start"),
"season_end": s.get("season_end"),
"colonies_managed": s["colonies_start"],
"colonies_lost": s["colonies_start"] - s["colonies_end"],
"colonies_survived": s["colonies_end"],
"loss_causes": ",".join(s.get("perceived_loss_causes", [])),
"operation_type": s.get("operation_size"),
"migratory": s.get("migratory"),
})
return rows
An application claims OHDS v1.0 conformance by satisfying all VODS v1.0 conformance rules (see VODS spec §6) and the following OHDS-specific rules.
"ohds_version": "1.0".inspections or apiary_summary array.inspection_date, apiary_ref, hive_ref, and colony_status. Each apiary summary includes apiary_ref, season, year, colonies_start, and colonies_end.null.apiary_ref and hive_ref values are generated per the active export_mode. In anonymous mode all refs are randomized per export. In tracked mode refs are stable per-program pseudonyms derived without exposing internal IDs.