taxify matches taxonomic names against locally stored Darwin Core backbone databases. Fifteen backbones are available, each compiled from a different authoritative source. The backbone we choose determines which names can be matched, what taxonomic opinion governs synonym resolution, and which extra metadata columns are available downstream. This vignette walks through the backbones, explains how to combine them in fallback chains, and offers practical guidance on which combination to pick for a given project.
Backend overview
The table below summarizes the fifteen backbones. “Approx. names” is the total number of name strings in the compiled backbone (accepted names plus synonyms); the actual species count is lower because each accepted species may have several synonym entries pointing to it.
| Backend | Full name | Scope | Approx. names | Source format |
|---|---|---|---|---|
wfo |
World Flora Online | Vascular plants, bryophytes | ~1.6M | Zenodo ZIP (classification.txt) |
col |
Catalogue of Life | All kingdoms | ~5.3M | ChecklistBank DwC-A (Taxon.tsv) |
gbif |
GBIF Backbone Taxonomy | All kingdoms | ~6.4M | GBIF simple.txt.gz (30 positional cols) |
itis |
Integrated Taxonomic Information System | All kingdoms, US focus | ~990k | SQLite dump from itis.gov |
ncbi |
NCBI Taxonomy | All life incl. viruses | ~2.7M | Pipe-delimited .dmp files (taxdump) |
ott |
Open Tree of Life | All life (synthetic) | ~3.7M | Pipe-delimited taxonomy.tsv + synonyms.tsv |
worms |
World Register of Marine Species | Marine and brackish | ~1.6M | ChecklistBank DwC-A |
euromed |
Euro+Med PlantBase | European/Mediterranean plants | ~147k | Semicolon-delimited CSV |
fungorum |
Species Fungorum Plus | Fungi | ~315k | ChecklistBank DwC-A |
algaebase |
AlgaeBase | Algae and cyanobacteria | ~170k | ChecklistBank DwC-A (CC BY-NC) |
fishbase |
FishBase | Fishes | ~100k | rfishbase (load_taxa + synonyms) |
sealifebase |
SeaLifeBase | Non-fish marine and aquatic | ~134k | rfishbase (load_taxa + synonyms) |
reptiledb |
Reptile Database | Reptiles | ~50k | reptarium taxa.csv + synonym/checklist XLSX |
lcvp |
Leipzig Catalogue of Vascular Plants | Vascular plants | ~1.3M | idiv-biodiversity tab_lcvp.rda (R data package) |
wcvp |
World Checklist of Vascular Plants (Kew) | Vascular plants | ~1.4M | Kew wcvp.zip (wcvp_names.csv) |
A few things stand out. WFO is the standard reference for plant taxonomy and the default backbone in taxify. It is maintained by the World Flora Online consortium and receives regular updates. The backbone includes all taxonomic ranks from kingdom down to form, with full synonym resolution and authorship.
COL and GBIF both cover all kingdoms, but they differ in curation strategy. COL is an expert-curated checklist assembled from over 160 sector databases, each maintained by a taxonomic authority for its group. GBIF’s backbone is assembled algorithmically from COL, ITIS, and dozens of other sources, which gives it broader raw coverage (~6.4M names vs COL’s ~5.3M) at the cost of occasional inconsistencies where source databases disagree. In practice, COL tends to give cleaner synonym resolution; GBIF tends to match more names.
ITIS was originally developed for North American fauna and remains
particularly strong on freshwater invertebrates, insects, and US-listed
species. Its coverage of non-American taxa is uneven. The ITIS backbone
is distributed as a SQLite dump; building it from source requires the
RSQLite package. Pre-built .vtr backbones avoid this
dependency.
NCBI Taxonomy is the gold standard for sequence-linked work. Every
GenBank, RefSeq, and BOLD sequence is linked to an NCBI tax_id, making
this backbone essential for molecular ecology and metagenomics. It is
also the only backbone that covers bacteria, archaea, and viruses in
meaningful depth. However, NCBI Taxonomy does not store authorship data,
so the authorship column is always NA for
NCBI-matched rows.
OTT (Open Tree of Life) is a synthetic taxonomy that merges NCBI,
GBIF, WoRMS, IRMNG, and several other sources into a single tree. It has
the broadest coverage of any single source and provides cross-references
to all of its constituent databases via the sourceinfo
field. The trade-off is that synthetic taxonomies can carry conflicts
and inconsistencies at the edges, where source databases disagree about
the placement of a taxon.
WoRMS is the authoritative source for marine species. It is curated by a network of over 300 taxonomic editors and covers marine, brackish, and some freshwater species. Beyond basic taxonomy, the WoRMS backbone stores habitat flags (marine, brackish, freshwater, terrestrial) and extinction status, some of which are accessible via the COL SpeciesProfile.
Euro+Med PlantBase is the taxonomic reference for the flora of Europe, the Mediterranean, and the Caucasus. It covers all native and introduced vascular plants in its geographic scope (~49k accepted names, ~83k synonyms). The backbone is built from the 2020 bulk download, updated via a PESI API delta refresh (April 2026) that resolved 1,014 reclassifications and synonym changes cross-referenced against WFO and POWO. Euro+Med is particularly useful for European vegetation surveys and datasets aligned with the European Vegetation Archive (EVA). Its data is licensed CC BY-SA 3.0.
Species Fungorum Plus is the specialist reference for fungal taxonomy, with ~315k names curated by the Royal Botanic Gardens, Kew. It covers Ascomycota, Basidiomycota, and other fungal phyla, including anamorphs and teleomorphs. For purely mycological datasets, it gives better synonym resolution than generalist databases.
AlgaeBase covers micro- and macroalgae, cyanobacteria, and some protists. It is the only backbone licensed CC BY-NC (non-commercial use only). All other backbones are open-access. taxify prints a license notice during AlgaeBase download to make this visible.
FishBase and SeaLifeBase are the standard references for aquatic
animals. FishBase covers fishes; SeaLifeBase covers the non-fish marine
and aquatic groups (molluscs, crustaceans, marine mammals, and the
rest). Both are compiled from the rfishbase package rather than a file
download, taking accepted species from load_taxa() and
synonym links from synonyms(). They carry species-rank rows
only, so their genera enter the genus register derived from those
species. The data is CC BY-NC 3.0.
The Reptile Database is the taxonomic reference for reptiles, with ~50k names covering snakes, lizards, turtles, crocodilians, and the tuatara. It is built from the reptarium bulk exports: the current accepted-species list, the periodic synonym snapshot, and the family-to-order checklist. The source carries no kingdom or class field, so the backbone stamps Animalia / Chordata / Reptilia on every row. The data is CC BY 4.0.
Downloading backbones
taxify auto-downloads backbones on first use. When we call
taxify(names, backbone = "wfo") and no local WFO backbone
exists, taxify fetches the pre-built .vtr file from Zenodo,
writes it to taxify_data_dir(), and caches the path for the
remainder of the R session. Subsequent calls, whether in the same
session or future sessions, reuse the local copy without any network
access.
To download a backbone ahead of time (useful on a shared server or in
a Docker image), use taxify_download():
library(taxify)
# Download one backbone
taxify_download("wfo")
# Download several at once
taxify_download(c("wfo", "col", "worms"))Pre-built .vtr files are hosted on Zenodo and typically
range from 50 MB (AlgaeBase) to 400 MB (GBIF), depending on the
backbone. The files are compiled from the raw Darwin Core sources with
precomputed matching keys, embedded synonym resolution, and genus-level
indexes, so they are ready for querying the moment the download
completes.
taxify checks for backbone updates once per R session. The first
taxify() call in a session fetches the manifest from
GitHub, compares each requested backbone’s local version against the
latest available release, and downloads a new version only if one
exists. If the network is unavailable, taxify falls back to the bundled
manifest and uses whatever local copy is on disk. The version check is
logged to the console so there are no silent updates.
For backbones with large source files, the build-from-source path
also exists. taxify_build("gbif") downloads the raw 1.5 GB
simple.txt.gz from GBIF, parses all 30 positional columns,
denormalizes the family hierarchy via self-joins, and compiles the
result into .vtr format. This is slower than downloading
the pre-built file but produces the same output. The build-from-source
path is mainly useful for CI pipelines or users who want to customize
the compilation step.
We can also pin a specific backbone version:
taxify_download("wfo", version = "2024.01")Pinned versions are stored in their own directory
(taxify_data_dir()/wfo/2024.01/) and are never overwritten
by future updates. The “latest” slot
(taxify_data_dir()/wfo/latest/) is always overwritten when
a newer version becomes available. Pinning is useful for
reproducibility: a project can lock a specific backbone version and
produce identical results regardless of when the analysis is re-run.
Single-backbone matching
The simplest use case: match plant names against WFO.
library(taxify)
plants <- c(
"Quercus robur",
"Quercus petraea",
"Pinus sylvestris",
"Acer pseudoplatanus",
"Betula pendula",
"Fagus sylvatica",
"Picea abies"
)
result <- taxify(plants, backbone = "wfo")
result[, c("input_name", "accepted_name", "family", "match_type", "backbone")]Every row in the output has 26 columns regardless of which backbone
produced it: input_name, matched_name,
accepted_name, taxon_id,
accepted_id, rank, family,
genus, epithet, authorship,
accepted_authorship, is_synonym,
is_hybrid, match_type,
fuzzy_dist, is_ambiguous,
ambiguous_targets, backbone,
backbone_version, kingdom_group,
taxon_group, life_form,
qualifier, qualifier_position,
aggregate_fallback, and hybrid_type. The
backbone column records "wfo" for matched rows
and NA for unmatched ones. The
backbone_version column records the backbone name, version,
and download date (e.g., "wfo:2024-12 (2026-04-01)") so we
can cite the exact data snapshot used.
When a name matches a synonym, taxify automatically resolves it to
the accepted name. The matched_name column shows the name
string that actually matched in the backbone (which may be a synonym),
while accepted_name shows the current accepted name after
resolution. The is_synonym column is TRUE for
resolved synonyms, FALSE for direct matches.
Fuzzy matching is on by default with a normalized Damerau-Levenshtein threshold of 0.2, roughly one edit per five characters. This catches common typos like transposed letters or missing diacritics. We can tighten the threshold for stricter matching:
result <- taxify(plants, backbone = "wfo", fuzzy_threshold = 0.1)Or disable fuzzy matching entirely to only accept exact and case-insensitive matches:
result <- taxify(plants, backbone = "wfo", fuzzy = FALSE)Two alternative distance metrics are available via the
fuzzy_method argument: "levenshtein" (standard
Levenshtein, no transposition handling) and "jw"
(Jaro-Winkler, better for names that differ mainly in their beginnings).
The default "dl" (Damerau-Levenshtein) is a good
all-rounder.
Backend-specific output differences
All fifteen backbones produce the same 26-column output schema. This is a deliberate design choice: downstream code does not need to know which backbone produced a match. That said, the content of those columns varies in ways worth knowing about.
Authorship. WFO’s scientificName is
already canonical (no authorship appended), so the
authorship column comes from a separate
scientificNameAuthorship field. COL and WoRMS store the
full scientificName with authorship included; taxify strips
it at build time to produce the canonical name used for matching, and
the stripped authorship is stored separately. NCBI and OTT have no
authorship data at all, so the authorship column is always
NA for those backbones. GBIF and ITIS provide authorship.
Euro+Med provides authorship from its AuthorString field.
Species Fungorum and AlgaeBase provide authorship from their DwC-A
archives.
Taxon IDs. Each backbone uses a different identifier
system. WFO IDs look like "wfo-0000000123". COL IDs are
opaque alphanumeric strings like "4LHBG". GBIF uses integer
keys ("2878688"). ITIS uses TSN integers
("183671"). NCBI uses NCBI Taxonomy IDs
("9606"). OTT uses OTT IDs ("770315"). WoRMS
uses AphiaIDs extracted from LSIDs; during build time, taxify strips the
urn:lsid:marinespecies.org:taxname: prefix and stores just
the numeric ID. Euro+Med uses TaxonUsageID integers from
the PlantBase export. Species Fungorum and AlgaeBase use ChecklistBank
dataset-specific IDs. All IDs are stored as character strings in the
taxon_id and accepted_id columns for
consistency, but their format is backbone-specific and meaningful only
within that backbone’s ecosystem. A taxon_id from WFO
cannot be looked up in the COL database, and vice versa.
Classification depth. The base output always
includes family and genus. WFO provides these
directly from its classification file. COL stores the full Linnaean
hierarchy (kingdom through order) in the Taxon.tsv, though these extra
columns require add_col_info() to access. GBIF provides
family through a denormalized family_key self-join at build
time. ITIS, NCBI, and OTT resolve family and genus via parent-hierarchy
walks during backbone compilation; the walk traverses up to 25 levels of
the taxonomic tree. WoRMS has denormalized classification columns
directly in its DwC-A. Euro+Med resolves family and genus via a
hierarchy walk on IsChildTaxonOfID. The genus register
(covered later in this vignette) fills in higher classification fields
(kingdom_group, taxon_group,
life_form) for all backbones.
Synonym handling. The backbones represent synonymy
in very different ways internally. WFO and COL use the Darwin Core field
acceptedNameUsageID to point from a synonym row to its
accepted name. GBIF encodes synonyms via parent_key
pointing to the accepted taxon. NCBI represents synonyms as alternative
name strings for the same tax_id; during build, taxify
emits these as separate rows with synthetic IDs of the form
"123456_syn_1", "123456_syn_2", etc. OTT uses
a separate synonyms.tsv file with explicit
synonym-to-accepted mappings. All of these representations are
normalized at build time into the same is_synonym +
accepted_name + accepted_id schema, so the
output looks the same regardless of source.
Synonym chains. Some backbones contain chained
synonyms, where synonym A points to synonym B, which points to accepted
name C. taxify resolves these chains at build time (up to 10 hops) so
the accepted_name always points to the terminal accepted
name. This happens transparently during backbone compilation and does
not affect query-time performance.
Multi-backbone fallback chains
When a species list spans multiple kingdoms, a single backbone may not cover everything. A wetland monitoring dataset might contain vascular plants, invertebrates, amphibians, algae, and fungi. No single backbone covers all of these equally well. taxify’s fallback chain handles this: we pass a vector of backbone names, and names are matched against each backbone in order. A name matched by an earlier backbone is never re-matched by a later one; it is removed from the pool.
mixed <- c(
"Quercus robur", # plant
"Panthera leo", # animal
"Amanita muscaria", # fungus
"Salmo trutta", # fish
"Escherichia coli" # bacterium
)
result <- taxify(mixed, backbone = c("wfo", "col", "gbif"))
result[, c("input_name", "accepted_name", "match_type", "backbone")]The console output during matching shows the chain in action:
Matching 5 names against 3 backbones: wfo -> col -> gbif
[wfo] Matching 5 names...
[col] Matching 4 remaining names...
[gbif] Matching 1 remaining names...
"Quercus robur" matches in WFO and is removed from the
pool. The remaining four names go to COL. If any are still unmatched
after COL (perhaps an obscure bacterial name), they go to GBIF. The
process continues until all names have been tried against all backbones
or all names have matched.
The order of backbones in the vector matters. It determines which
taxonomic opinion wins for each name. If "Quercus robur"
exists in both WFO and COL, putting WFO first means WFO’s taxonomic
opinion is used (its accepted name, family assignment, synonym
resolution). Putting COL first would give COL’s opinion. For names that
exist in multiple backbones, the first backbone in the chain always
wins.
This has practical consequences. If we put GBIF first, everything
would match there (GBIF has ~6.4M names, the largest of any backbone)
and the curated opinions from WFO, COL, or WoRMS would never be
consulted. For a plant-heavy list with some non-plant taxa mixed in,
c("wfo", "col") or c("wfo", "col", "gbif") is
a sensible ordering: we get WFO’s curated plant taxonomy for plants, and
COL or GBIF picks up the rest.
If all names have been matched by earlier backbones, later backbones are skipped entirely with a message:
[gbif] Skipped (all names matched)
Fuzzy matching runs independently within each backbone in the chain. A name that fails exact matching in WFO gets fuzzy-matched against WFO. If it still fails, it moves to the next backbone and gets exact-matched, then fuzzy-matched there. This means a misspelled plant name has the best chance of matching in WFO (the plant-specialist backbone) before falling through to COL or GBIF.
Worked example: plants-only with WFO vs WFO + COL
WFO focuses on accepted vascular plant and bryophyte names. Its coverage is excellent for current taxonomy, but names that appear only in older literature, belong to genera not yet integrated into WFO, or are nomenclaturally orphaned (no clear accepted name) may be absent. COL inherits WFO’s plant taxonomy as one of its sector databases but supplements it with names from other sources, including historical synonyms and cultivar names.
plants <- c(
"Quercus robur",
"Quercus petraea",
"Pinus sylvestris",
"Acer pseudoplatanus",
"Coffea arabica",
"Welwitschia mirabilis",
"Lepidodendron aculeatum", # extinct lycopsid
"Nothofagus cunninghamii",
"Dracaena draco"
)
# WFO alone
wfo_result <- taxify(plants, backbone = "wfo")
table(wfo_result$match_type)If any names come back as "none", we can add COL as a
fallback:
# WFO first, COL as fallback
both_result <- taxify(plants, backbone = c("wfo", "col"))
table(both_result$match_type)
both_result[, c("input_name", "accepted_name", "backbone")]The backbone column now shows "wfo" for
names matched by WFO and "col" for names that only COL
could resolve. This tells us exactly where each match came from, which
matters for reproducibility. In a paper’s methods section, we can state
“plant names were resolved against WFO 2024-12, with unmatched names
resolved against COL 2025.”
The two-backbone chain is especially valuable for large vegetation plot datasets. Most names resolve in WFO with its plant-optimized taxonomy, but the handful of edge cases (cultivars, historical names, genera recently moved between families) that fall through to COL would otherwise require manual resolution.
Worked example: mixed-kingdom list with COL + GBIF + WoRMS
An ecological monitoring dataset from a coastal estuary might contain vascular plants, invertebrates, fish, and marine algae. No single backbone covers all of these well. COL has broad expert-curated coverage across kingdoms. GBIF fills gaps with its larger name pool. WoRMS provides an authoritative backstop for marine invertebrate synonymy, which can be slow to propagate to generalist databases.
estuary_species <- c(
"Zostera marina", # seagrass (plant)
"Salicornia europaea", # glasswort (plant)
"Carcinus maenas", # shore crab
"Mytilus edulis", # blue mussel
"Platichthys flesus", # European flounder
"Nereis diversicolor", # ragworm
"Fucus vesiculosus", # bladderwrack (brown alga)
"Littorina littorea", # common periwinkle
"Arenicola marina", # lugworm
"Cerastoderma edule" # common cockle
)
result <- taxify(estuary_species, backbone = c("col", "gbif", "worms"))
result[, c("input_name", "accepted_name", "family", "backbone")]COL is a good first choice here because it covers all kingdoms with expert curation. Most of these names will resolve there. GBIF catches anything COL might miss, including names from national checklists that have not yet been incorporated into COL. WoRMS serves as a final backstop specifically for marine taxa, covering invertebrate synonyms that may lag in generalist databases. The chain is ordered from highest curation to broadest coverage.
If the list were predominantly marine with only a few terrestrial taxa, we might lead with WoRMS instead to ensure its authoritative marine taxonomy takes precedence:
Worked example: fungi with Species Fungorum + COL fallback
Mycological datasets benefit from using Species Fungorum Plus as the primary backbone. It is curated specifically for fungi, with ~315k names including anamorphs, teleomorphs, and the pleomorphic naming changes introduced by the 2011 Melbourne Code. Synonym coverage for fungal genera is better than in generalist databases, where fungal taxonomy is often a secondary concern.
fungi <- c(
"Amanita muscaria",
"Boletus edulis",
"Cantharellus cibarius",
"Tuber melanosporum",
"Saccharomyces cerevisiae",
"Aspergillus niger",
"Penicillium chrysogenum",
"Agaricus bisporus",
"Trametes versicolor",
"Cordyceps militaris"
)
result <- taxify(fungi, backbone = c("fungorum", "col"))
result[, c("input_name", "accepted_name", "is_synonym", "backbone")]Species Fungorum resolves the standard names. If any obscure, recently described, or historically orphaned species fall through, COL picks them up. For mixed datasets that include both fungi and plants, a three-backbone chain works well:
mixed <- c(
"Quercus robur", # plant
"Amanita muscaria", # fungus
"Lactarius deliciosus", # fungus
"Pinus sylvestris", # plant
"Russula emetica" # fungus
)
result <- taxify(mixed, backbone = c("wfo", "fungorum", "col"))WFO handles plants, Species Fungorum handles fungi, and COL serves as
a catch-all for anything that falls through both specialist backbones.
The genus register (see below) helps taxify skip backbones that cannot
possibly match a given name. When taxify encounters
"Amanita muscaria" and the genus Amanita is
not in WFO’s coverage table, the name is marked out-of-scope for WFO
immediately and passed to the next backbone without wasting time on
fuzzy matching.
Worked example: algae
For algal taxonomy, AlgaeBase is the specialist source. It covers micro- and macroalgae, cyanobacteria, and some protists. Its curation is particularly strong for freshwater and marine microalgae where generalist databases often have thin coverage and outdated synonymy.
algae <- c(
"Chlamydomonas reinhardtii",
"Chlorella vulgaris",
"Ulva lactuca",
"Fucus vesiculosus",
"Sargassum muticum"
)
result <- taxify(algae, backbone = c("algaebase", "col"))
result[, c("input_name", "accepted_name", "backbone")]AlgaeBase is licensed CC BY-NC. taxify prints a license notice during download so users are aware of the restriction before incorporating the data into a workflow. For commercial applications, COL or WoRMS can serve as alternatives, though with less specialized algal coverage.
Worked example: molecular ecology with NCBI
When reconciling species lists from metabarcoding or eDNA studies, names are often linked to NCBI accessions. Using the NCBI backbone ensures that taxify’s accepted names align with the same taxonomy used in GenBank and BOLD.
edna_hits <- c(
"Salmo trutta",
"Phoxinus phoxinus",
"Anguilla anguilla",
"Cottus gobio",
"Lampetra planeri",
"Chironomus riparius", # midge (insect)
"Potamopyrgus antipodarum" # New Zealand mud snail
)
result <- taxify(edna_hits, backbone = c("ncbi", "col"))
result[, c("input_name", "accepted_name", "taxon_id", "backbone")]The taxon_id values for NCBI-matched rows are NCBI
tax_ids, which can be used directly to link back to GenBank records or
NCBI taxonomy pages. For names not found in NCBI (e.g., taxa without
sequenced representatives), COL provides a fallback.
The backbone column
The backbone column in taxify’s output is a plain
character column. For single-backbone calls, every matched row shows the
same backbone name. For multi-backbone chains, the column records which
backbone produced each match. Unmatched rows have
backbone = NA.
We can use this column to count how many names each backbone resolved:
result <- taxify(species_list, backbone = c("wfo", "col", "gbif"))
table(result$backbone, useNA = "ifany")Or filter to rows matched by a specific backbone:
wfo_matches <- result[result$backbone == "wfo" & !is.na(result$backbone), ]
col_matches <- result[result$backbone == "col" & !is.na(result$backbone), ]This is useful for quality control. If we expected a purely plant-based list but see many names matched by COL instead of WFO, that tells us the list contains names outside WFO’s scope (perhaps algae classified as plants in older literature, or animal-associated organisms like plant parasites).
The backbone_version column gives the full provenance
string for each row, combining the backbone name, version, and download
date. For a paper’s methods section, we can extract the unique versions
used:
unique(result$backbone_version[!is.na(result$backbone_version)])
# e.g., c("wfo:2024-12 (2026-04-01)", "col:2025 (2026-04-01)")These provenance strings identify both the taxonomic source and the exact snapshot used, making results fully reproducible even if the backbone releases a new version between when we run the analysis and when a reviewer checks it.
Backend-specific extras
Three backbones have dedicated enrichment functions that join
additional backbone-specific columns to a taxify result. These functions
only enrich rows that were matched by the corresponding backbone; rows
from other backbones get NA in the new columns.
WFO extras: add_wfo_info()
Adds WFO-specific columns: scientificNameID,
parentNameUsageID, namePublishedIn,
higherClassification, taxonRemarks, and
infraspecificEpithet. The namePublishedIn
field is particularly useful for citing original descriptions, and
higherClassification provides the full taxonomic hierarchy
as a semicolon-separated string.
result <- taxify(plants, backbone = "wfo") |>
add_wfo_info()
result[, c("input_name", "accepted_name", "namePublishedIn")]COL extras: add_col_info()
Adds COL classification columns (kingdom,
phylum, col_class, order),
nomenclatural metadata (notho,
nomenclaturalCode, nomenclaturalStatus,
namePublishedIn), infraspecificEpithet, and
SpeciesProfile flags (is_extinct, is_marine,
is_freshwater, is_terrestrial). The
class column is renamed to col_class to avoid
conflict with R’s class() function.
The SpeciesProfile flags come from a separate file in the COL DwC-A archive. They are especially useful for filtering: we can, for instance, exclude extinct species from a contemporary biodiversity analysis, or separate marine from terrestrial taxa in an estuarine dataset.
result <- taxify(species_list, backbone = "col") |>
add_col_info()
# Check which species are marine
result[result$is_marine == TRUE & !is.na(result$is_marine),
c("input_name", "accepted_name", "kingdom", "is_marine")]GBIF extras: add_gbif_info()
Adds GBIF-specific columns: notho_type (hybrid type),
nom_status (nomenclatural status),
bracket_authorship (basionym author),
bracket_year, gbif_year,
name_published_in, origin (how the name
entered the GBIF backbone), and infra_specific_epithet. The
origin field is useful for understanding provenance: values
like "SOURCE", "DENORMED_CLASSIFICATION", or
"VERBATIM_ACCEPTED" indicate how GBIF ingested the
name.
result <- taxify(species_list, backbone = "gbif") |>
add_gbif_info()
result[, c("input_name", "accepted_name", "origin", "nom_status")]Combining extras in a multi-backbone result
In a multi-backbone result, we can pipe through multiple enrichment functions. Each one only touches rows from its own backbone; the others are left alone.
result <- taxify(species_list, backbone = c("wfo", "col", "gbif")) |>
add_wfo_info() |>
add_col_info() |>
add_gbif_info()This produces a wide data.frame with the union of all extra columns.
For a given row, only the columns from its backbone are populated; the
rest are NA. Whether this is useful depends on the
analysis. For most workflows, the base 26 columns are sufficient, and
backbone-specific extras are only needed when we require nomenclatural
details, habitat flags, or publication references that the standard
output does not include.
The genus register
taxify builds a unified genus register from the union of genera
across the backbones you have installed (up to all fifteen: WFO, COL,
GBIF, ITIS, NCBI, OTT, WoRMS, Euro+Med, Species Fungorum, AlgaeBase,
FishBase, SeaLifeBase, Reptile Database, LCVP, and WCVP). Build it with
taxify_build_register() (equivalently
taxify_download("register")); it reads each installed
backbone once and stores the result under the data directory. With all
fifteen installed the register holds ~500k genera, each with its family,
higher classification (kingdom through order, where available), and a
life_form label (e.g., "vascular plant",
"animal", "fungus"). The classification is
resolved by priority: WoRMS > COL > GBIF > Euro+Med > ITIS
> NCBI > OTT > WFO. If COL and WFO disagree about which family
a genus belongs to, COL’s assignment wins.
The register serves two purposes in taxify’s matching pipeline.
First, it provides life_form, kingdom_group,
and taxon_group columns in taxify output for every matched
name, regardless of which backbone matched it. These columns make it
possible to stratify results by broad taxonomic group without needing to
look up each family manually.
Second, the register enables out-of-scope detection. Before fuzzy
matching begins, taxify checks whether an unmatched name’s genus is in
the register. If the genus is known (it appears in the register) but not
covered by any of the requested backbones (it does not appear in the
backbone coverage table), taxify marks the name as
"out_of_scope" immediately. This avoids wasting time on
fuzzy matching against a backbone that could never produce a match, and
gives the user a more informative signal than a plain
"none".
Looking up a genus
lookup_genus() returns the register row for a single
genus. The register is loaded into memory on first call and cached for
the session.
lookup_genus("Quercus")
# genus kingdom phylum class order family life_form
# 1 Quercus Plantae ... ... Fagales Fagaceae vascular plant
lookup_genus("Panthera")
# genus kingdom phylum class order family life_form
# 1 Panthera Animalia Chordata Mammalia Carnivora Felidae animalChecking backbone coverage
taxify_register_coverage() shows which backbones contain
a given genus and at what version. This is useful when diagnosing match
failures: if the genus does not appear in the coverage table for the
requested backbone, the name is genuinely out of scope for that
backbone.
taxify_register_coverage("Quercus")
# genus backbone version date_added
# 1 Quercus col 2025 2026-04-01
# 2 Quercus gbif current 2026-04-01
# 3 Quercus wfo 2024-12 2026-04-01A genus covered by all three backbones can be matched by any of them. A genus covered only by GBIF (perhaps a recently described bacterial genus) will not match against WFO or COL.
Out-of-scope detection in practice
When taxify encounters an unmatched name whose genus appears in the
register but is not covered by any of the requested backbones, it sets
match_type = "out_of_scope" instead of "none".
This distinction carries information: an out-of-scope result means the
name likely exists in a different backbone rather than being a
misspelling or invalid name.
# Trying to match a marine invertebrate against WFO (plants only)
result <- taxify("Carcinus maenas", backbone = "wfo")
result$match_type
# [1] "out_of_scope"
result$life_form
# [1] "animal"The life_form column tells us the genus belongs to
animals, confirming that WFO is the wrong backbone for this name. In a
pipeline, we can filter for "out_of_scope" rows and re-run
them against a broader backbone. Or, more practically, we include the
right backbones in the fallback chain from the start, and the
out-of-scope mechanism saves time by skipping the fuzzy matching step
for names that cannot possibly match.
The taxify result’s print() method includes a tally of
out-of-scope names broken down by taxon_group, making it
easy to see at a glance what kinds of organisms were outside the
requested backbone’s scope.
Practical guidance: choosing backbones
The right backbone depends on the taxonomic scope of the data. Here is a decision tree organized by the most common use cases.
Pure vascular plant lists. Use
backbone = "wfo". WFO is the standard reference,
well-curated, and updated regularly. If some names fall through (e.g.,
horticultural cultivars, nomenclaturally complex genera, or names from
older floras that use outdated synonymy), add COL:
backbone = c("wfo", "col").
European vegetation data. Use
backbone = c("euromed", "wfo"). Euro+Med PlantBase is the
taxonomic reference used by EVA and covers all native and introduced
vascular plants of Europe, the Mediterranean, and the Caucasus. Leading
with Euro+Med ensures European synonym resolution follows Euro+Med’s
taxonomic opinion, with WFO as fallback for non-European taxa or names
outside Euro+Med’s scope. Note that Euro+Med data is CC BY-SA 3.0.
Pure marine/aquatic lists. Use
backbone = "worms". WoRMS is the authoritative source for
marine taxonomy, curated by domain experts, and includes habitat and
extinction flags. For estuarine or transitional lists that include some
terrestrial taxa, add COL:
backbone = c("worms", "col").
Pure fungal lists. Use
backbone = "fungorum". Species Fungorum Plus is the
specialist reference for fungi. Add COL as fallback for obscure or
recently described species:
backbone = c("fungorum", "col").
Pure algal lists. Use
backbone = "algaebase". Add COL or WoRMS as fallback:
backbone = c("algaebase", "col"). Remember AlgaeBase is CC
BY-NC.
Mixed-kingdom ecological datasets. Use
backbone = c("col", "gbif"), or lead with a specialist
backbone for the dominant taxon group. For a plant-dominated dataset
with some animals and fungi: backbone = c("wfo", "col").
For a marine biodiversity survey:
backbone = c("worms", "col", "gbif"). For a forest
inventory that includes trees, fungi, insects, and epiphytes:
backbone = c("wfo", "fungorum", "col").
Molecular/sequence-linked work. Use
backbone = "ncbi". NCBI Taxonomy is the reference for
GenBank, BOLD, and other sequence databases. It covers bacteria,
archaea, and viruses that other backbones lack. For mixed molecular and
ecological work: backbone = c("ncbi", "col").
Phylogenetic studies. Use
backbone = "ott". OTT is the backbone of the Open Tree of
Life and merges multiple source taxonomies. Its cross-references to
NCBI, GBIF, WoRMS, and IRMNG make it a good bridge between different
identifier systems.
Maximum coverage / catch-all. Use
backbone = c("col", "gbif"). COL provides expert-curated
taxonomy for ~5.3M names. GBIF’s backbone adds ~6.4M names from
additional sources. Together they cover virtually all described species
with a nomenclatural record. This combination is a reasonable default
when the taxonomic composition of the dataset is unknown.
General rule. Specialist backbones first, generalist
backbones second. Lead with the backbone whose taxonomic opinion we
trust most for the dominant taxon group, and add broader backbones as
fallbacks for the remainder. The backbone column in the
output lets us audit exactly which taxonomic opinion was applied to each
name.
Performance considerations
Backend size affects download time and, to a lesser extent, matching speed. WFO (~1.6M names) matches faster than GBIF (~6.4M names) for the same query. However, taxify uses index-accelerated genus-blocked joins at the C level (via vectra), so even GBIF matching is fast for typical species lists. A list of 5,000 names resolves against GBIF in under a second on modern hardware. The performance difference only becomes noticeable at scale (100k+ names) or with heavy fuzzy matching against a large backbone.
For large lists with a multi-backbone chain, putting the most likely
backbone first saves time. Names matched by the first backbone skip all
later backbones entirely. If 90% of a list is plants,
c("wfo", "col") is faster than c("col", "wfo")
because WFO is smaller and resolves most names on the first pass. The
remaining 10% of names go to COL, which is larger but only processes the
small residual.
Fuzzy matching is the most expensive step. It runs a genus-blocked fuzzy join with multi-threaded string distance computation. For names with misspelled genera (where genus blocking cannot help), taxify falls back to a 2-character prefix block that catches most genus-level typos while keeping the search space manageable.
Reproducibility
The backbone_version column encodes the exact data
snapshot used. For a published analysis, we recommend recording these
strings in the methods section or supplementary material. taxify pins
the backbone version at download time and does not update mid-session.
Version checks happen once per R session, and any update is logged to
the console with the old and new version numbers.
To lock a specific backbone version for a project:
taxify_download("wfo", version = "2024.01")Pinned versions live in their own directories and are never
overwritten. The “latest” slot continues to track new releases
independently. A project that needs exact reproducibility can pin all
backbones at specific versions and never use the “latest” slot. A
project that prefers to stay current can rely on the default “latest”
behavior and cite the backbone_version strings from the
output.
The manifest, which maps backbone names to their download URLs and
latest versions, is cached per session and can be refreshed with
taxify_refresh_manifest(). For offline use, taxify falls
back to the bundled manifest shipped with the package.