@UVALIDATE
@UVALIDATE is a REDCap action tag that validates a field against a check character (ISO/IEC 7064, Damm, Verhoeff, Luhn) or a regex format pattern, live as the value is typed.
@UVALIDATE is the module's flagship rule. It recomputes a field's
check character, tests its format against a regex pattern, or both — and reports
the two kinds of failure separately, so the person entering data knows which
mistake they made.
Syntax
The tag has three forms, from shortest to most explicit. All three go in a field's Field Annotation box in the Online Designer.
@UVALIDATE bare — all defaults (ISO 7064 Mod 37,36)
@UVALIDATE=verhoeff short — pick the algorithm
@UVALIDATE={"algorithm":"verhoeff","blockSave":"hard"} JSON — every option
Algorithm shorthands
@UVALIDATE=verhoeff
@UVALIDATE=9710 ISO 7064 Mod 97,10
@UVALIDATE=3736 ISO 7064 Mod 37,36 (the default)
@UVALIDATE=gs1 GS1 / GTIN / EAN / UPC barcodes
@UVALIDATE=isbn ISBN-10 weighted Mod-11
Format patterns instead of a check character
Set algorithm to none (or regex) and give a
pattern. In stock REDCap a custom regex validation type has to be added
server-wide by an administrator; here a project designer sets it per rule.
@UVALIDATE={"algorithm":"none","pattern":"FC[0-9]{4}"}
@UVALIDATE={"algorithm":"regex","pattern":"TB-[0-9]{6}","blockSave":"hard"}
Both at once
@UVALIDATE={"algorithm":"iso7064_mod37_36","pattern":"TB[A-Z]{3}-[0-9]{5}[0-9A-Z]"}
@UVALIDATE={"algorithm":"mod11_10","source":"digits_only"}
@UVALIDATE={"algorithm":"3736","strip":"-/ _|\\"}
Pooled fields
One box holding several IDs — space-separated, comma-separated, or run together with no separator — is split at the boundaries where the check character verifies, then shown as one chip per member.
Several ID formats in one field
Give the rule a list of alternates instead of one
pattern/algorithm. A value — or a token inside a
pooled box — is valid if any one entry accepts it, so IDs from several
studies can share a field without the ones that carry a check character losing
it. Each entry needs its own pattern; a pooled rule also needs
lengths on every entry.
@UVALIDATE={"type":"pooled","strip":"-","blockSave":"hard","alternates":[
{"label":"GHIT", "pattern":"FC[1-9]-[0-9]{4}", "algorithm":"none","lengths":[8]},
{"label":"START4KIDS","pattern":"SK[1-9]-[0-9]{4}[0-9A-Z]","algorithm":"3736","lengths":[9]},
{"label":"DARETB", "pattern":"DT[1-9]-[0-9]{5}[0-9A-Z]","algorithm":"3736","lengths":[10]},
{"label":"SCREENTB", "pattern":"ST[1-9]-[0-9]{5}[0-9A-Z]","algorithm":"3736","lengths":[10]}]}
Entry keys: pattern (required), algorithm,
source, strip, lengths,
label; anything omitted falls back to the rule-level value. Up to 8
entries per rule. When alternates is used the rule-level
pattern, idLengths, idMinLen and
idMaxLen must be left unset.
A value that matches the pattern of a check-bearing entry must pass that entry's check character; format-only entries are tried only when no check-bearing pattern matches. Combinations that could report a mis-scan as a clean ID are refused when the rule is saved, each with a message naming the entry and the fix: lengths where one is the sum of two or more others, a format-only pattern that accepts a value a check-bearing pattern also accepts (in a pooled rule, between entries sharing a length), and entries that disagree about which characters survive cleaning. The overlap test is exact for ordinary patterns; a backreference, or lookaround it cannot settle, makes the rule refused rather than assumed safe. Plain character classes avoid it.
Patterns run as JavaScript in the browser and as PCRE on the server, so
syntax the two read differently is refused when the rule is saved:
\pL and \p{L}, \K \G \h \v \R \N \X \C
\Q…\E \g \z, POSIX classes such as [[:digit:]],
inline flags (?i) (?x), comments
(?#…), atomic groups (?>…) and an
empty class []. Explicit classes, (?:…),
lookahead, lookbehind and (?<name>…) all work.
Pooled fields
@UVALIDATE={"type":"pooled","idLengths":[9],"expectedIds":3}
@UVALIDATE={"type":"pooled","algorithm":"none","pattern":"FC[0-9]{4}","idLengths":[6]}
@UVALIDATE={"type":"pooled","idMinLen":9,"idMaxLen":12,"blockSave":"confirm"}
Methods supported
| Family | Members | Notes |
|---|---|---|
| ISO/IEC 7064 | Mod 37,36 (default), Mod 11,10, Mod 97,10, Mod 11,2, Mod 37,2, two letters-only variants | Alphanumeric payloads |
| Classic decimal | Damm, Verhoeff, Luhn | Digit payloads, one check digit |
| Weighted modulus | GS1 Mod-10, ABA Mod-10, ICAO MRZ Mod-10, ISBN-10 weighted Mod-11 | weighted_mod11 may emit X |
| None | none / regex | Format pattern only |
The three Mod-10 schemes catch every single-digit error at any length but miss
adjacent swaps of digits differing by 5. weighted_mod11 catches every
single-digit error and every adjacent swap only up to 9 digits — the ISBN-10 domain.
At 10 or more digits the position carrying weight 11 goes blind to substitutions, so
prefer Mod 11,2 or Mod 97,10 for longer numbers.
The method must match how the IDs were minted. A check character
is only meaningful against the scheme that produced it — pointing
@UVALIDATE at the wrong algorithm will reject valid IDs.
Conditional validation with when
Any rule may carry a condition and validate only while that condition is true.
@UVALIDATE={"algorithm":"verhoeff","when":"[specimen_type]='2'"}
@UVALIDATE={"algorithm":"none","pattern":"FC[0-9]{4}","when":"[consent(1)]='1' and [site]<>'9'"}
The condition language is a REDCap-style subset, not byte-for-byte REDCap logic:
| Supported | Rejected when the rule is saved |
|---|---|
[field] and [checkbox(code)] references | Functions such as datediff(...) |
'text', "text" and number literals | Smart variables such as [record-name] |
= <> != > < >= <= | [event][field] cross-event prefixes |
and / or / not, parentheses | Arithmetic and piping |
Branched validation
Several @UVALIDATE tags with different when conditions on
one field branch, plus at most one tag without a condition as the fallback.
@UVALIDATE={"algorithm":"verhoeff","when":"[specimen_type]='2'"}
@UVALIDATE={"algorithm":"none","pattern":"FC[0-9]{4}"} ← the "otherwise"
The "should end in X" hint
A hint naming the expected check character is available per rule via
suggestFix, but it is off by default. A visible expected
character can entice staff to force-fit a mistyped ID instead of re-scanning it.
@UVALIDATE={"algorithm":"3736","suggestFix":true,"note":"Blood specimen barcode"}
Field types
Check-character and regex validation apply to Text and Notes fields. The other rule kinds cover a wider set — see each tag's page.