This is the symbol reference for the spatial document model: the types a document is made of,
their exact fields, and every exported function and method you can call on them. Look a name up
here; read The document model for how the model is built and
Extracting fields for how it is used.
Three packages are covered — document (the analysed document and its result types), reading
(reading-order analysis) and field (form-field detection and field packs). Names are given
unqualified when they belong to document, and package-qualified otherwise.
Every symbol here is reachable from both documented surfaces: the
kis CLI and the deployed
rules.svc . A rule obtains the document with
bbox.Get("<name>") and calls these methods on it; the mapping from rule text to method is
in The rules bridge .
Convention Rule Receiver Methods are on *Document unless the table header says otherwise Numbers Method parameters and returns use int64 and float64 only — never int, int32 or float32 Struct fields Exported fields still use plain int; the numeric contract covers signatures, not fields Pages 1-indexed. 0 means “every page” on HeaderText, FooterText and Headings Missing results Queries return the zero value (empty slice, "", 0, nil) — they do not error Safe*Returns a non-nil empty result where the plain variant returns nil
Nothing is populated until Analyze() runs
New copies the pages and the configuration and nothing else. Blocks, Lines, Tables,
Fields, Checkboxes, PageLayouts, FontAnalysis, Stats and the spatial index are all
nil or zero until Analyze (or AnalyzeParallel) completes, and every query below silently
returns empty in that state rather than reporting a problem. Both surfaces analyse every document
they load before the first rule is evaluated, so a rule never sees the unanalysed state — this
describes what Analyze is responsible for, not a step you perform.
Analyze returns error, but the per-page worker returns nil unconditionally: a malformed
document surfaces as empty results, never as an error.
type BoundingBox struct {
X0 , Y0 float64 // Top-left corner
X1 , Y1 float64 // Bottom-right corner
Top-left origin, Y increasing downward, in raw OCR units. Nothing is normalised to 0..1.
Method Returns Width() float64X1 - X0Height() float64Y1 - Y0Area() float64Width() * Height()CenterX() float64(X0 + X1) / 2CenterY() float64(Y0 + Y1) / 2Left() float64X0Right() float64X1Top() float64Y0Bottom() float64Y1IsZero() boolTrue when all four coordinates are within 1e-9 of zero Contains(x, y float64) boolTrue when the point is inside, edges included
DirRight Direction = iota // 0
Method or function Returns (Direction) String() string"right", "left", "above", "below", else "unknown"DirectionFromString(s string) DirectionParses right, left, above/up, below/down
Two Direction types, same names, different numbers
The geometry layer declares DirLeft=0, DirRight=1, DirAbove=2, DirBelow=3 — left and right
are swapped relative to the table above. The library converts between them explicitly, so
results are correct, but a direction carried as a number across that boundary flips.
Always name a direction with a string. DirectionFromString and its geometry counterpart both
return below for an unrecognised string.
Value float64 // Score from 0.0 to 1.0
Level string // "VeryLow", "Low", "Medium", "High", "VeryHigh"
Method Returns IsHigh() boolValue >= 0.8IsMedium() boolValue >= 0.5 && Value < 0.8IsLow() boolValue < 0.5Percent() float64Value * 100
Level and the predicates cut at different points
Level is bucketed at 0.9 / 0.8 / 0.6 / 0.4; the predicates cut at 0.8 / 0.5. A value of 0.55
reports Level == "Low" and IsMedium() == true simultaneously. Pick one vocabulary per rule
set and stay with it.
Type Fields TextBlockText string, Box BoundingBox, Confidence float64, Page intTextLineText string, Box BoundingBox, Confidence float64, Page int, IsWrapped boolDocumentStatsMedianCharWidth, MedianLineHeight, MedianWordGap, MedianLineGap, PageWidth, PageHeight — all float64PageLayoutResultPage int, Width float64, Height float64, ColumnCount int, HasHeader bool, HasFooter bool, Margins MarginsResultMarginsResultTop, Bottom, Left, Right — all float64RegionResultType string (Header, Footer, MainContent, LeftMargin, RightMargin), Box BoundingBox, Page int, Text string, Confidence float64DocumentSummaryPageCount, BlockCount, LineCount, TableCount, FieldCount, CheckboxCount, CheckboxGroups — all int — plus Stats text.DocStats
TextBlock is lossy against the analysis-layer block: it drops the source words, the line id and
the merge score, so it cannot answer “was this block merged, and from what”. Use the
internal-typed accessors when you need that provenance.
Checkboxes []checkbox.Checkbox
CheckboxGroups []checkbox.CheckboxGroup
PageLayouts [] * region.PageLayout
SpecialRegions []special.Region
Signatures []special.Region
Handwriting []special.Region
Barcodes []special.Region
FontAnalysis * font.FontAnalysis
Pages is the input; everything else is filled by Analyze. Signatures, Handwriting and
Barcodes are projections of SpecialRegions, not separate detections.
Method or function Returns New(ocrDoc *ocr.Document) *DocumentWraps an OCR document with DefaultConfig(). Does not analyse NewWithConfig(ocrDoc *ocr.Document, cfg Config) *DocumentSame, with explicit settings DefaultConfig() ConfigEvery detector on, DPI 300 Analyze() errorRuns the full pipeline. Always returns nil today AnalyzeParallel(workers int64) errorPer-page parallel analysis; results match the serial path AnalyzeParallelContext(ctx context.Context, workers int64) errorCancellable parallel analysis SetDPI(dpi float64)Overrides the scan resolution used for point-size conversion Debug(value bool)Sets debug logging Toggledebug()Flips debug logging SetSchemas(schemas map[string]*jsonschema.Schema)Installs named extraction schemas Schema(name string) *jsonschema.SchemaReturns an installed schema, nil when absent Summary() DocumentSummaryCounts and statistics for the analysed document InvalidateReadingCache()Drops the cached reading-order result
DetectSpecialRegions bool
MergeConfig text.MergeConfig
Field Default Effect MergeWordstrueGlue adjacent OCR words into blocks. Off means one block per word DetectTablestruePopulates Tables DetectFieldstruePopulates Fields DetectCheckboxestruePopulates Checkboxes and CheckboxGroups DetectRegionstruePopulates PageLayouts DetectSpecialRegionstruePopulates SpecialRegions and its three projections AnalyzeFontstruePopulates FontAnalysis SpellCheckfalseDeclared but never read by the pipeline ExtractPatternstrueDeclared but never read — pattern extraction is lazy, built on first Find/Has/Count BuildSpatialIndextrueBuilds the R-tree. Without it the k-nearest, directional and radius queries return nil DPI300.0Point-size conversion basis. <= 0 falls back to 300 MergeConfig— Word-merge thresholds
Constant Value DefaultDPI300.0DefaultBaselineTolerance0.3DefaultAlignTolerance0.3DefaultMaxWordGapMultiplier5.0DefaultCapHeightRatio0.72DefaultXHeightRatio0.50DefaultAscenderRatio0.85DefaultMaxLabelLength50DefaultFontSizeRoundingPrecision10.0DefaultFuzzyDistance2DefaultMaxGap5UnlimitedDistance-1 (float64)
These return the flat wrapper types above.
Method Returns GetBlocks() []TextBlockEvery block in the document GetLines() []TextLineEvery reconstructed line GetPageBlocks(pageNum int64) []TextBlockBlocks on one page GetPageTextLines(pageNum int64) []TextLineLines on one page FindTextBlocks(search string) []TextBlockBlocks containing the text FindAnchorBlocks(anchorText string) []TextBlockBlocks matching an anchor FindFuzzyBlocks(search string, maxDist int64) []TextBlockBlocks within an edit distance GetHeadingTextBlocks() []TextBlockBlocks classified as headings GetBlocksByFontSizeRange(minPt, maxPt float64) []TextBlockBlocks inside a point-size band GetDocumentStats() DocumentStatsThe six document medians and page dimensions
These return the analysis types instead of the wrappers, keeping provenance.
Method Returns GetPage(pageNum int64) []text.BlockMerged blocks on one page GetPageLines(pageNum int64) []text.LineReconstructed lines on one page GetField(label string) *field.FieldA detected field by label GetTable(containing string) *table.TableThe first table containing the text GetPageLayout(pageNum int64) *region.PageLayoutFull layout record for a page GetHeader(pageNum int64) *region.RegionHeader region GetFooter(pageNum int64) *region.RegionFooter region GetMainContent(pageNum int64) *region.RegionMain-content region GetCheckboxByLabel(label string) *checkbox.CheckboxA detected checkbox GetCheckboxGroup(name string) *checkbox.CheckboxGroupA detected checkbox group GetCheckedValue(groupName string) []stringSelected labels in a group ExtractByDefinition(def field.FieldDef) *field.FieldExtract one field from an explicit definition ExtractRegisteredFields() map[string]*field.FieldExtract every field definition registered by a pack
Method Returns GetLayout(pageNum int64) *PageLayoutResultPage dimensions, column count, header/footer flags, margins GetHeaderRegion(pageNum int64) *RegionResultHeader region with its text GetFooterRegion(pageNum int64) *RegionResultFooter region with its text GetMainContentRegion(pageNum int64) *RegionResultMain-content region with its text
Method Returns AllLines() []stringEvery line’s text LineCount() int64Number of lines BlockCount() int64Number of blocks LineAt(index int64) stringLine by 0-based index FirstLine() string / LastLine() stringFirst and last line TopLines(n int64) []string / BottomLines(n int64) []stringFirst and last n lines LineContaining(text string) stringFirst line containing the text FullLineContaining(text string) stringThe whole line containing the text, untrimmed LineNumberOf(text string) int64Index of the first line containing the text LineNumbersOf(text string) []int64Indexes of every matching line LinesContaining(text string) []stringEvery line containing the text LinesMatching(pattern string) []stringEvery line matching a regular expression LineRange(start, end int64) []stringLines in an index range LinesAfter(anchorText string, n int64) []stringn lines after an anchorLinesBefore(anchorText string, n int64) []stringn lines before an anchorLinesBetween(startText, endText string) []stringLines between two anchors
Method Returns PageCount() int64Highest page number across blocks FieldCount() int64Detected fields TableCount() int64Detected tables CheckboxCount() int64Detected checkboxes SignatureCount() int64Detected signatures BarcodeCount() int64Detected barcodes ColumnCount() int64Detected columns CountOccurrences(text string) int64Occurrences of a string
PageCount() is not len(Pages)
The analysis-layer PageCount() int64 is the maximum Page value across blocks . It is 0
before Analyze() and 0 for a document whose pages carry no words. The OCR-layer
Document.PageCount() int is the real page count.
Wrapper-typed, using BoundingBox and Point:
Method Returns BlocksInBox(box BoundingBox) []TextBlockBlocks fully inside the box BlocksIntersectingBox(box BoundingBox) []TextBlockBlocks overlapping the box NearestBlocks(point Point, k int64) []TextBlockThe k nearest blocks NearestBlockIn(from BoundingBox, dir Direction, maxDist, margin float64) *TextBlockNearest block in a direction BlocksNearPoint(center Point, radius float64) []TextBlockBlocks within a radius
Geometry-typed equivalents, returning text.Block:
Method Returns BlocksInRegion(region geometry.Box) []text.BlockBlocks fully inside the region BlocksIntersecting(region geometry.Box) []text.BlockBlocks overlapping the region KNearestBlocks(point geometry.Point, k int64) []text.BlockThe k nearest blocks NearestBlockInDirection(from geometry.Box, dir geometry.Direction, maxDist, margin float64) *text.BlockNearest block in a direction BlocksWithinRadius(center geometry.Point, radius float64) []text.BlockBlocks within a radius
KNearestBlocks, NearestBlockInDirection and BlocksWithinRadius all read the R-tree — they
return nil when Config.BuildSpatialIndex was off.
Each returns a chainable query.QueryResult.
Method Anchor semantics After(anchorText string) query.QueryResultRight-of first, then below Below(anchorText string) query.QueryResultDirectly below Above(anchorText string) query.QueryResultDirectly above RightOf(anchorText string) query.QueryResultDirectly right LeftOf(anchorText string) query.QueryResultDirectly left Near(anchorText string) query.QueryResultAny direction, nearest first QueryBetween(startText, endText string) query.QueryResultBetween two anchors InRegion(x0, y0, x1, y1 float64) query.QueryResultAbsolute coordinates InRegionPct(x0Pct, y0Pct, x1Pct, y1Pct float64) query.QueryResultPercentages of the page
Percentage regions collapse to nothing when page dimensions are zero
InRegionPct scales by Stats.PageWidth and Stats.PageHeight. When a page declares no size
and the extent fallback cannot recover one, both stay zero, the region becomes (0,0,0,0) and
every percentage query matches nothing — with no error anywhere. On a multi-page document the
two values are an average across pages, so mixing letter and legal pages scales every
percentage query against a page size that matches none of them.
QueryResult carries Blocks []text.Block, Box geometry.Box, Found bool, Page int64 and
these accessors:
Method Returns Text(), Lines(), Count(), IsEmpty()Text, line list, block count, emptiness FirstText(), FirstNumber(), FirstCurrency(), FirstDate(), FirstValue()First match, typed Containing(substr), MatchingPattern(pattern), Filter(predicate)Narrowing ContainingPhraseFuzzy, ContainingIPhraseFuzzy, ContainingAnyPhraseFuzzy, ContainingAnyIPhraseFuzzyFuzzy narrowing, each (phrase string, maxDistPerWord, maxTotalDist int64)
Method Returns ReadAll() stringWhole document in reading order ReadPage(page int64) stringOne page in reading order MainContent() stringMain-content region text BodyText() stringBody text, headers and footers excluded HeaderText(page int64) string / FooterText(page int64) stringRegion text; 0 means all pages InHeader(text string) bool / InFooter(text string) boolRegion containment Contains(text string) boolReading-order text contains the string ContainsAll(texts ...string) bool / ContainsAny(texts ...string) boolAll / any Title() stringDetected title, "" when none HasTitle(text string) bool / TitleContains(text string) boolExact / substring TitleMatches(pattern string) boolRegular expression against the title Outline() []reading.OutlineEntryNested heading structure Headings(level int64) []stringHeadings at a level; 0 returns every level AllHeadings() []stringEvery heading Sections() []reading.SectionLogical sections Section(heading string) *reading.SectionOne section; falls back to a case-insensitive substring match and recurses into subsections TextUnder(heading string) stringText under a heading TextBetween(startHeading, endHeading string) stringText between two headings Columns() []reading.Column / Column(index int64) *reading.ColumnDetected columns IsMultiColumn() bool / IsMultiPage() boolShape predicates
The reading result is computed once and cached. InvalidateReadingCache() drops it.
type AnalyzerConfig struct {
DetectColumns bool // default true
DetectHeadings bool // default true
RespectRegions bool // default true; declared but never read
MaxColumns int // default 4; 0 means auto
Method or function Returns DefaultAnalyzerConfig() AnalyzerConfigThe defaults above NewAnalyzer() *AnalyzerAnalyzer with defaults NewAnalyzerWithConfig(config AnalyzerConfig) *AnalyzerAnalyzer with explicit settings (*Analyzer) Analyze(blocks []text.Block, docStats text.DocStats) *ReadingResultFull analysis using document medians (*Analyzer) AnalyzeWithMedian(blocks []text.Block, medianHeight, medianCharWidth float64) *ReadingResultAnalysis with explicit medians (*Analyzer) QuickAnalyze(blocks []text.Block) *ReadingResultAnalysis with medians derived from the blocks
Type Fields ReadingResultBlocks []ReadingBlock, Outline []OutlineEntry, Sections []Section, Columns []Column, Title string, PageCount intReadingBlockembeds text.Block; ContentType ContentType, ReadingOrder int, Level int, Column int, RegionType RegionType OutlineEntryText string, Level int, Box geometry.Box, Page int, Children []OutlineEntry, ContentStart int, ContentEnd intSectionHeading string, Level int, Blocks []ReadingBlock, Subsections []Section, Box geometry.Box, Page intColumnIndex int, Box geometry.Box, Blocks []ReadingBlock, Page int
Method Returns (*ReadingResult) Text() stringEvery block’s text, newline-joined (*ReadingResult) TextByPage(page int) stringOne page, newline-joined (*ReadingResult) Headings(level int) []stringHeadings at a level; 0 returns all (*Section) Text() stringHeading plus content plus subsections (*Section) TextWithOptions(includeHeading bool, lineSeparator string) stringSame, configurable (*Column) Text() string / (*Column) Lines() []stringColumn text as one string or per block
Classification enums:
Type Values ContentTypeContentUnknown, ContentTitle, ContentHeading, ContentSubheading, ContentBody, ContentCaption, ContentFootnote, ContentPageNumber, ContentListItem, ContentTableCellRegionTypeRegionUnknown, RegionHeader, RegionBody, RegionFooter, RegionLeftMargin, RegionRightMargin
Both have String() string returning the name without the prefix ("Heading", "Footer").
Reading-order constants: HeaderRegionRatio 0.12, FooterRegionRatio 0.10,
TitleSearchRegionRatio 0.35, TitleFontSizeMultiplier 1.5,
HeadingFontSizeMultiplier 1.2, ColumnGapMinMultiplier 3.0, SameLineTolerance 0.3.
Region bands ignore the declared page size
The analyser computes its own page width and height as 1.05× the maximum X1/Y1 across
every block in the document . It never reads the page’s declared dimensions. The header band
(top 12%), footer band (bottom 10%), margin bands and title search region are therefore relative
to the pooled printed extent, so classification drifts on a document whose last page is short or
whose pages differ in size.
Method Returns ContainsText(text string) boolSubstring anywhere ContainsAnyText(texts ...string) bool / ContainsAllText(texts ...string) boolAny / all
Method Returns HasPhrase(phrase string) boolMulti-word phrase present HasPhraseOnPage(phrase string, page int64) boolScoped to a page HasPhraseInBox(phrase string, box geometry.Box) boolScoped to a box HasAnyPhrase(phrases ...string) bool / HasAllPhrases(phrases ...string) boolAny / all HasAnyPhraseOnPage(page int64, phrases ...string) boolAny, page-scoped HasAnyPhraseInBox(box geometry.Box, phrases ...string) boolAny, box-scoped CountPhrase(phrase string) int64Occurrences CountPhraseOnPage(phrase string, page int64) int64Occurrences on a page PhraseNear(a, b string, maxPixels float64) boolTwo phrases within a pixel distance PhraseBetween(startAnchor, endAnchor string) stringText between two phrases FindPhrase(phrase string, linesBefore, linesAfter int64) []PhraseMatchMatches with line context FindIPhrase(phrase string, linesBefore, linesAfter int64) []PhraseMatchSame, case-insensitive
Method Returns HasPhraseFuzzy(phrase string, maxDistancePerWord int64) boolPresent within an edit distance HasPhraseOnPageFuzzy(phrase string, page int64, maxDistancePerWord int64) boolPage-scoped HasPhraseInBoxFuzzy(phrase string, box geometry.Box, maxDistancePerWord int64) boolBox-scoped HasAnyPhraseFuzzy(maxDistancePerWord int64, phrases ...string) boolAny HasAllPhrasesFuzzy(maxDistancePerWord int64, phrases ...string) boolAll CountPhraseFuzzy(phrase string, maxDistancePerWord int64) int64Occurrences FindPhraseFuzzy(phrase string, maxDistancePerWord, maxTotalDistance, linesBefore, linesAfter int64) []FuzzyPhraseMatchMatches with distances FindIPhraseFuzzy(phrase string, maxDistancePerWord, maxTotalDistance, linesBefore, linesAfter int64) []FuzzyPhraseMatchSame, case-insensitive
type PhraseMatch struct {
Phrase string // The matched phrase text
Page int // Page number where found
Box geometry.Box // Bounding box of the phrase
LineIndex int // Index of the line containing the phrase
MatchedLine string // Full text of the line containing the match
LinesBefore [] string // Lines before the match (context)
LinesAfter [] string // Lines after the match (context)
Blocks []text.Block // The blocks that form this phrase
type FuzzyPhraseMatch struct {
TotalDistance int // Total edit distance across all words
MatchedWords [] string // The actual words that matched
Method Returns FindText(search string) []text.BlockBlocks containing the text FindAnchor(anchorText string) []text.BlockBlocks matching an anchor FindFuzzy(search string, maxDist int64) []text.BlockBlocks within an edit distance FindNgram(tokens ...string) []anchor.NgramMatchUnordered n-gram matches FindNextFuzzy(search string, fuzzymaxDist int64, from geometry.Box, dir geometry.Direction, maxDistance float64) *text.BlockNext fuzzy match in a direction FindNextFuzzyWithNgram(search string, fuzzymaxDist int64, from geometry.Box, dir geometry.Direction, maxDistance float64) *anchor.NgramMatchSame, returning the n-gram match ExtractAfter(label string, dir anchor.RelativeDir) []text.BlockBlocks after a label in a relative direction
Method Returns ExtractSnippet(startPhrase, endPhrase string, caseInsensitive, includeEnd bool) *SnippetText between two phrases, across pages. nil when the start phrase is absent ExtractSnippetFuzzy(startPhrase, endPhrase string, caseInsensitive, includeEnd bool, maxDist int64) *SnippetSame, fuzzy
StartPhrase string // The starting phrase that was matched
EndPhrase string // The ending phrase that was matched
StartPage int // Page where the start phrase was found
EndPage int // Page where the end phrase was found
Lines [] string // The extracted lines of text
The start phrase is included; the end phrase is excluded unless includeEnd is true.
Method Returns GetOCRText(expr string, opts OCRTextOptions) stringText found by walking an anchor expression GetOCRTextWithContext(ctx context.Context, expr string, opts OCRTextOptions) stringCancellable variant GetOCRTextSimple(expr string, direction string, ngramMaxDistance float64, maxDistance float64, margin float64) stringSame, with the options flattened to primitives FindMatchingBlock(expr string, ngramMaxDistance float64) *text.BlockThe block an expression resolves to FindMatchingBlockWithContext(ctx context.Context, expr string, ngramMaxDistance float64) *text.BlockCancellable variant
type OCRTextOptions struct {
Direction geometry.Direction // search direction from the matched anchor
NgramMaxDistance float64 // 0 = unlimited
MaxDistance float64 // -1 = unlimited
Margin float64 // padding added to the search area
DefaultOCRTextOptions() OCRTextOptions returns DirBelow, 0, UnlimitedDistance, 0.
Method Returns Find(patternName string) []PatternMatchEvery match of a named pattern FindFirst(patternName string) stringFirst match, "" when none Has(patternName string) boolAny match Count(patternName string) int64Match count FindPattern(pattern string) []PatternMatchMatches of an explicit pattern FindPatternFirst(pattern string) stringFirst explicit-pattern match HasPattern(pattern string) bool / PatternCount(pattern string) int64Presence and count ExtractPatterns() []pattern.MatchEvery pattern match in the document ExtractDates() []pattern.Match / ExtractCurrency() []pattern.MatchTyped extraction
type PatternMatch struct {
Value string // The matched text
Box geometry.Box // Bounding box of the matched text
Page int // Page number where the match was found
BlockIndex int // Index of the block containing the match
A value split across blocks by OCR is only found by the spanning family.
Method Returns FindSpanning(patternName string) []pattern.BlockMatchMatches spanning blocks FindSpanningAll() []pattern.BlockMatchEvery spanning match HasSpanning(patternName string) bool / CountSpanning(patternName string) int64Presence and count
Fifteen types have a dedicated four-method set. Every method takes no arguments; the four
signatures are the same for every type:
func ( d * Document) Find < T > () []PatternMatch
func ( d * Document) Find < T > First () string
func ( d * Document) Has < T > () bool
func ( d * Document) < T > Count () int64
Type All matches First match Presence Count SSN FindSSN()FindSSNFirst()HasSSN()SSNCount()Phone FindPhone()FindPhoneFirst()HasPhone()PhoneCount()Email FindEmail()FindEmailFirst()HasEmail()EmailCount()Date FindDate()FindDateFirst()HasDate()DateCount()Currency FindCurrency()FindCurrencyFirst()HasCurrency()CurrencyCount()Percentage FindPercentage()FindPercentageFirst()HasPercentage()PercentageCount()Account number FindAccountNumber()FindAccountNumberFirst()HasAccountNumber()AccountNumberCount()Routing number FindRoutingNumber()FindRoutingNumberFirst()HasRoutingNumber()RoutingNumberCount()ZIP code FindZipCode()FindZipCodeFirst()HasZipCode()ZipCodeCount()EIN FindEIN()FindEINFirst()HasEIN()EINCount()Street address FindStreetAddress()FindStreetAddressFirst()HasStreetAddress()StreetAddressCount()State FindState()FindStateFirst()HasState()StateCount()ITIN FindITIN()FindITINFirst()HasITIN()ITINCount()VIN FindVIN()FindVINFirst()HasVIN()VINCount()Policy number FindPolicyNumber()FindPolicyNumberFirst()HasPolicyNumber()PolicyNumberCount()
FindDate and ExtractDates are different functions
FindDate() []PatternMatch and FindCurrency() []PatternMatch are the pattern-family methods
above. ExtractDates() []pattern.Match and ExtractCurrency() []pattern.Match return the
analysis-layer match type instead. The names are close; the return types are not interchangeable.
Method Returns Field(label string) query.FieldResultA detected field by label FieldByPattern(labelPattern string) query.FieldResultBy regular expression over labels AllFields() []field.FieldEvery detected field FieldExists(label string) boolPresence FieldValue(label string) stringValue as text FieldEquals(label, expected string) bool / FieldContains(label, substr string) boolComparison FieldNumber(label string) float64 / FieldCurrency(label string) float64Numeric parse ExtractFields(fieldLabels ...string) *FormDataSeveral fields plus every table
Fields map [ string ]query.FieldResult
Method Returns (*FormData) Get(label string) query.FieldResultOne field (*FormData) Table(index int) *TableResultOne table (*FormData) HasField(label string) boolField was found (*FormData) MissingFields() []stringLabels with no value (*FormData) IsComplete() boolNothing missing (*FormData) ToMap() map[string]stringFlat label-to-value map
Method Returns TextRightOf(anchorText string) stringText to the right of an anchor TextBelow(anchorText string) stringText below an anchor TextAbove(anchorText string) stringText above an anchor TextLeftOf(anchorText string) stringText to the left of an anchor NumberRightOf(anchorText string) float64Numeric parse of TextRightOf NumberBelow(anchorText string) float64Numeric parse of TextBelow CurrencyRightOf(anchorText string) float64Currency parse of TextRightOf CurrencyBelow(anchorText string) float64Currency parse of TextBelow FuzzyTextNear(label string, dir Direction, maxDistPerWord, maxTotalDist int64, expand float64) stringFuzzy label, text in a direction FuzzyTextNearCapped(label string, dir Direction, maxDistPerWord, maxTotalDist int64, expand, maxExtent float64) stringSame, with a hard extent cap FuzzyTextNearChain(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand float64) stringMulti-hop anchor chain FuzzyTextNearChainCapped(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand, maxExtent float64) stringChain with an extent cap FuzzyTextNearChainScaled(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand, multiplier float64) stringChain with a scaled search region FuzzyTextAtIntersection(rowLabel, colLabel string, maxDistPerWord, maxTotalDist int64, expand float64) stringValue at a row/column crossing HasFuzzyChain(chain string, maxDistPerWord, maxTotalDist int64, searchMultiplier, maxSearchPx, sideExtMultiplier float64) boolChain resolves HasIFuzzyChain(chain string, maxDistPerWord, maxTotalDist int64, searchMultiplier, maxSearchPx, sideExtMultiplier float64) boolSame, case-insensitive
A chain is |-delimited, every segment but the last carrying a direction in angle brackets —
"Loan Information<below>|Loan Term".
Method Returns FieldNear(label string, dir Direction, maxDistPerWord, maxTotalDist int64, expand float64) query.FieldResultScored spatial extraction FieldNearCapped(label string, dir Direction, maxDistPerWord, maxTotalDist int64, expand, maxExtent float64) query.FieldResultScored, extent-capped FieldNearChain(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand float64) query.FieldResultScored chain FieldNearChainCapped(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand, maxExtent float64) query.FieldResultScored chain, extent-capped ScoredField(label string) query.FieldResultRight-of and below, higher score wins ScoredFieldOnPage(label string, page int64) query.FieldResultSame, page-scoped ExtractFieldsScored(labels []string) map[string]query.FieldResultSeveral fields, scored ExtractFieldsScoredOnPage(labels []string, page int64) map[string]query.FieldResultSame, page-scoped ExtractFieldsJSON(labels []string) stringJSON object of ScoredValue ExtractFieldsJSONOnPage(labels []string, page int64) stringSame, page-scoped
type ScoredValue struct {
Value string ` json:"value" `
Confidence float64 ` json:"confidence" ` // 0..1
Found bool ` json:"found" `
Page int64 ` json:"page,omitempty" `
Method string ` json:"method,omitempty" ` // e.g. "field.right_of", "field.below"
query.FieldResult carries Value, Label, Box, LabelBox, Conf, Prov, Found and
Page. Read it with AsText, AsNumber, AsCurrency, AsPercent, AsPercentRaw, AsInt,
AsBool, AsDate; test it with IsEmpty, Equals, Contains, Matches, OneOf,
GreaterThan, LessThan, Between, Before, After; and inspect the score with
Confidence, ConfidencePct, ConfidenceScore, IsConfident, NeedsReview, Explain,
Provenance. Required, Optional, Or, OrDefault, WithConfidence and WithProvenance
return a modified copy.
Method Returns ExtractRepeatingFields(labels ...string) []field.RecordOne record per repeat of the label set RepeatingExtractingFields(repextractFields string, extractMaxLines, extractMaxWords int64, extractEnd, extractFieldWords, extractVerticalFields string) []map[string]anySame, driven entirely by strings
Method or function Returns (*Document) ExtractColumnAlignedSection(sectionStart, sectionEnd, columnHeaders string) []map[string]anyRows read from a columnar section PostprocessRows(rows []map[string]any, key string, fn string) []map[string]anyPackage function; applies a named transform to one key in every row
fn accepts trim, upper, lower, normalize_spaces, trim_currency, and the dynamic form
ExtractRegex("pattern", "defaultVal"). An unknown fn returns the rows untouched. Call it
again to chain a second transform on the same key.
Confidence float64 // overall confidence
LabelConfidence confidence.Score
ValueConfidence confidence.Score
OverallScore confidence.Score
PatternType pattern.PatternType
LabelPatterns [] string // regular expressions for the label
LabelAnchors [] * anchor.Ngram // n-gram anchors for the label
ValueType pattern.PatternType
LocationHint RelationType
Validator func ( string ) bool
Type Fields FieldGroupName string, Fields []Field, Box geometry.BoxPackName string, Fields []FieldDefRecordFields map[string]string, Line text.LineDetectorNo exported fields RelationTypeRelInline, RelRightOf, RelBelow, RelTableCell
Method or function Returns NewDetector() *DetectorA detector with default pattern, anchor and fuzzy settings (*Detector) DetectFields(blocks []text.Block, lines []text.Line) []FieldInline, right-of and below detection, deduplicated (*Detector) ExtractByDefinition(def FieldDef, blocks []text.Block, lines []text.Line) *FieldOne field from an explicit definition GroupFields(fields []Field, maxGap float64) []FieldGroupClusters fields by vertical proximity (*Field) ComputeOverallConfidence()Sets OverallScore and Confidence from a 0.4/0.6 weighting of label and value
Field packs carry the vertical vocabulary; the library itself is domain-neutral.
Function Returns RegisterPack(p Pack)Appends a pack. Concurrency-safe; duplicate names are not rejected RegisteredPacks() []PackSnapshot in registration order RegisteredFieldDefs() []FieldDefEvery definition across every pack RegisteredFieldDef(name string) *FieldDefFirst match by name, case-insensitive; nil when absent ResetPacks()Empties the registry
When two packs define the same field name, RegisteredFieldDef returns the one registered
first — later registrations do not override earlier ones.
Repeating extraction is configured with a chainable builder:
Method or function Returns NewRepeatingFieldExtractor(labels ...string) *RepeatingFieldExtractorPackage function; MaxLines 10, MaxWords 3, MinMatchRatio 0.5 (*RepeatingFieldExtractor) SetEndMarkers(markers ...string) *RepeatingFieldExtractorText that ends a record (*RepeatingFieldExtractor) SetMaxLines(n int) *RepeatingFieldExtractorLines per record (*RepeatingFieldExtractor) SetMaxWords(n int) *RepeatingFieldExtractorDefault words per value (*RepeatingFieldExtractor) SetFieldMaxWords(label string, n int) *RepeatingFieldExtractorWords for one field (*RepeatingFieldExtractor) SetVerticalFields(labels ...string) *RepeatingFieldExtractorFields whose value sits below the label (*RepeatingFieldExtractor) Extract(lines []text.Line) []RecordOne record per repeat
type RepeatingFieldExtractor struct {
FieldMaxWords map [ string ] int
Field-detection constants: DefaultMaxLabelLength 50, DefaultShortLabelLength 20,
DefaultLabelConfidenceNormalizationFactor 100.0, DefaultGapToWidthMultiplier 3.0,
DefaultAlignmentToleranceRatio 0.5, DefaultBaselineTolerance 0.3,
DefaultBaseLabelScore 0.5, DefaultColonBoost 0.3, DefaultShortLabelBoost 0.1,
DefaultCapitalBoost 0.1, DefaultDigitPenalty 0.2,
DefaultPatternMatchConfidence 0.95.
Method Returns AllTables() []table.TableEvery detected table FirstTable() *table.TableThe first table TableAt(index int64) *table.TableBy index TableNear(anchorText string) *table.TableNearest to an anchor TableNearPhrase(anchorPhrase string) *table.TableNearest to a phrase HasTables() boolAny table detected Table(index int64) *TableResultBy index, wrapped TableContaining(text string) *TableResultFirst table containing the text SafeTable(index int64) *SafeTableResultBy index, nil-safe WrapTable(t *table.Table) *TableResultWraps a table; nil in, nil out
Method Returns TableBelow(anchor string) *TableResultFirst table below an anchor TableAbove(anchor string) *TableResultFirst table above an anchor TableBetween(startAnchor, endAnchor string) *TableResultTable between two anchors TablesBetween(startAnchor, endAnchor string) []*TableResultEvery table between two anchors TableBelowFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *TableResultFuzzy anchor TableAboveFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *TableResultFuzzy anchor TableBetweenFuzzy(startAnchor, endAnchor string, maxDistPerWord, maxTotalDist int64) *TableResultFuzzy anchors
Nil-safe variants of the same lookups:
Method Returns SafeTableBelow(anchor string) *SafeTableResultFirst table below an anchor SafeTableAbove(anchor string) *SafeTableResultFirst table above an anchor SafeTableBetween(startAnchor, endAnchor string) *SafeTableResultTable between two anchors SafeTableBelowFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultFuzzy anchor SafeTableAboveFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultFuzzy anchor SafeTableBetweenFuzzy(startAnchor, endAnchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultFuzzy anchors SafeTablesBetween(startAnchor, endAnchor string) []*TableResultEvery table between two anchors
SafeTablesBetween adds no safety
Every other SafeTable* method returns *SafeTableResult. SafeTablesBetween returns
[]*TableResult and its body is a direct call to TablesBetween — the name is the only
difference. Each element dereferences like a plain TableResult.
TableResult embeds *table.Table.
Method Returns Row(index int) *RowResultRow by index, headers included DataRow(index int) *RowResultRow by index, headers excluded DataRowCount() intRows excluding headers Headers() []string / HasHeaders() boolHeader row CellValue(row, col int) stringCell by position DataCell(row, col int) stringCell by position, headers excluded CellByHeader(row int, header string) stringCell by row index and header name ColumnByIndex(index int) []string / ColumnByName(header string) []stringColumn values ColumnData(colIndex int) []stringColumn values excluding the header FindRow(text string) *RowResultFirst row containing the text FindColumn(text string) intIndex of the column containing the text, -1 when absent RowsAsMaps() []map[string]stringRows keyed by header AsMap() map[string][]stringColumns keyed by header IsColumnRightAligned(colIndex int) bool / IsColumnLeftAligned(colIndex int) boolAlignment tests ColumnAlignment(colIndex int) stringAlignment name RightAlignedColumns() []intIndexes of right-aligned columns — usually the numeric ones
RowResult embeds *table.Row and adds three accessors:
Method Returns (*RowResult) Cell(col int) stringCell by column index (*RowResult) CellByHeader(header string) stringCell by header name (*RowResult) Values() []stringEvery cell in the row
SafeTableResult embeds *TableResult and returns empties instead of nil dereferences.
Method Returns Row(index int) *SafeRowResult / DataRow(index int) *SafeRowResultNever nil Cell(row, col int) string / DataCell(row, col int) string"" when absentCellByHeader(row int, header string) string"" when absentRowCount() int, DataRowCount() int, ColumnCount() int0 on an absent tableHasData() bool / IsEmpty() boolEmptiness RowsAsMaps() []map[string]string / AsMap() map[string][]stringEmpty on an absent table
SafeRowResult embeds *RowResult and overrides its accessors to be nil-safe.
Method Returns (*SafeRowResult) Cell(col int) string"" when absent(*SafeRowResult) CellByHeader(header string) string"" when absent(*SafeRowResult) Values() []stringEmpty slice on an absent row (*SafeRowResult) IsEmpty() boolTrue on an absent row
Row int // Row index (0-based)
Col int // Column index (0-based)
Text string // Cell text content
Box BoundingBox // Cell bounding box
IsHeader bool // True if this is a header cell
Confidence float64 // Detection confidence
Method Returns AsText() stringTrimmed text AsNumber() float64Number, 0 on a parse failure AsCurrency() float64Currency with symbols and separators stripped AsPercent() float64Percentage AsInt() intInteger AsDate() time.TimeDate, zero time on a parse failure IsEmpty() boolNo text Contains(substr string) bool / Equals(text string) boolComparison
Every accessor is nil-safe on the receiver.
type CheckboxResult struct {
Label string // Associated label text
Checked bool // Whether the checkbox is selected
Confidence float64 // Detection confidence (0.0-1.0)
Box BoundingBox // Checkbox location
Type string // "checkbox", "radio", "bracket", etc.
GroupName string // Name of the group this checkbox belongs to
type CheckboxGroupResult struct {
Name string // Group identifier
Options []CheckboxResult // All checkboxes in the group
Selected [] string // Labels of selected items
IsMultiple bool // True if multiple selections are allowed
Page int // Page number where the group appears
Confidence float64 // Overall group detection confidence
Method Returns (*CheckboxResult) IsChecked() boolfalse on a nil receiver(*CheckboxResult) HasLabel() boolA label was associated (*CheckboxResult) IsHighConfidence() boolConfidence >= 0.8 (*CheckboxGroupResult) SelectedValue() stringFirst selection, "" when none (*CheckboxGroupResult) SelectedValues() []stringEvery selection (*CheckboxGroupResult) HasSelection() boolAnything selected (*CheckboxGroupResult) OptionCount() intOptions in the group (*CheckboxGroupResult) IsYesSelected() bool / IsNoSelected() boolYes/No groups (*CheckboxGroupResult) GetOption(label string) *CheckboxResultOne option by label
On the document:
Method Returns GetCheckbox(label string) *CheckboxResultOne checkbox GetAllCheckboxes() []CheckboxResultEvery checkbox GetCheckboxGroupResult(name string) *CheckboxGroupResultOne group GetAllCheckboxGroups() []CheckboxGroupResultEvery group IsCheckboxChecked(label string) boolState by label GetCheckboxValue(label string) stringValue by label IsYesNoChecked(groupName string) boolYes/No group state
When detection misses the box but the OCR carries a marker glyph, the marker family reads the
glyph instead:
Method Returns CheckedOption(options ...string) stringFirst option with a checked marker to its left CheckedOptionMarkers(options []string, checkedChars string) stringSame, with an explicit marker set CheckedOptionOnPage(options []string, page int64) stringPage-scoped CheckedOptionNear(anchor string, dir Direction, extent float64, options []string) stringScoped to a region near an anchor CheckedOptionNearMarkers(anchor string, dir Direction, extent float64, options []string, checkedChars string) stringSame, with an explicit marker set
DefaultCheckedMarkers is "@®©■•✓✔☑█"; DefaultUncheckedMarkers is "O○□()" and is
informational only — the checked set is what matching uses.
type SpecialRegionType string
RegionSignature SpecialRegionType = " Signature "
RegionHandwriting SpecialRegionType = " Handwriting "
RegionBarcode1D SpecialRegionType = " Barcode1D "
RegionBarcodeQR SpecialRegionType = " QRCode "
RegionBarcode2D SpecialRegionType = " Barcode2D "
type SpecialRegionResult struct {
Type SpecialRegionType // Type of special region
Box BoundingBox // Region location
Confidence float64 // Detection confidence (0.0-1.0)
NearLabel string // Nearby label text, e.g. "Sign here"
OCRText string // Any OCR text found in the region
Method Returns IsSignature() bool, IsHandwriting() boolType tests IsBarcode() boolTrue for any of the three barcode types IsQRCode() bool, Is1DBarcode() boolNarrow barcode tests IsHighConfidence() bool, IsMediumConfidence() boolConfidence bands HasNearbyLabel() boolNearLabel is setString() stringOne-line summary
On the document:
Method Returns HasSignatures() bool, HasHandwriting() bool, HasBarcodes() boolPresence GetSignatures(pageNum int64) []SpecialRegionResultSignatures on a page GetAllSignatures() []SpecialRegionResultEvery signature GetAllHandwriting() []SpecialRegionResultEvery handwriting region GetAllBarcodes() []SpecialRegionResultEvery barcode GetAllSpecialRegions() []SpecialRegionResultEverything detected GetHighConfidenceSignatures() []special.RegionSignatures above the confidence bar GetSignaturesOnPage(pageNum int64) []special.RegionInternal-typed, page-scoped GetHandwritingOnPage(pageNum int64) []special.RegionInternal-typed, page-scoped GetBarcodesOnPage(pageNum int64) []special.RegionInternal-typed, page-scoped GetSpecialRegionsByConfidence(minConfidence float64) []special.RegionInternal-typed, filtered
Method Returns GetFontSize(block text.Block) font.SizeEstimated size for a block GetLineFontSize(line text.Line) font.SizeEstimated size for a line GetFontSizeForText(searchText string) float64Size of the block containing the text GetBodyFontSize() float64Median body size GetHeadingSizes() []float64Distinct heading sizes GetBlocksByFontSize(minPt, maxPt float64) []text.BlockBlocks inside a point band GetHeadingBlocks() []text.BlockBlocks classified as headings IsHeading(block text.Block) boolHeading classification IsHeadingPhrase(phrase string) boolThe phrase sits in a heading IsHeadingPhraseFirst(phrase string) boolOnly the first match is tested IsHeadingPhraseInRegion(phrase, regionName string) boolHeading test inside a named region IsHeadingPhraseIn(phrase, direction, regionName string, page int64, firstMatchOnly bool) boolHeading test, fully scoped IsSmallText(block text.Block) boolSmall or fine print, per the font analysis. false when fonts were not analysed IsTextBig(searchText string) boolThe block containing the text is taller than average IsBold(block text.Block) boolWeight estimate from stroke width StrokeWidth(block text.Block) float64Estimated stroke width TypographyTier(block text.Block) font.TierSize tier IsAllCaps(block text.Block) bool / IsTitleCase(block text.Block) boolCasing IsCentered(block text.Block) boolHorizontally centred on the page within 5%, using Stats.PageWidth IsCenteredInBox(block text.Block, box geometry.Box, tolerancePct float64) boolCentred inside a box
Install schemas with SetSchemas, then extract by name.
Method Returns HasForm(name string) bool / HasTable(name string) boolA schema of that kind is installed ExtractForm(name string) map[string]anyField values for a form schema ExtractFormOnPage(name string, page int64) map[string]anyPage-scoped ExtractTable(name string) []map[string]anyRows for a table schema ExtractTableOnPage(name string, page int64) []map[string]anyPage-scoped SafeExtractForm(name string) map[string]anyNon-nil empty instead of nil SafeExtractFormOnPage(name string, page int64) map[string]anyNon-nil empty, page-scoped SafeExtractTable(name string) []map[string]anyNon-nil empty instead of nil SafeExtractTableOnPage(name string, page int64) []map[string]anyNon-nil empty, page-scoped ExtractFormScored(name string) map[string]query.FieldResultForm values with confidence ExtractFormScoredOnPage(name string, page int64) map[string]query.FieldResultSame, page-scoped DiagnoseForm(name string) []FieldDiagnosisWhy each property did or did not extract
type FieldDiagnosis struct {
AnchorInScope bool // matched at the configured tolerance within the schema's page/region
AnchorAnywhere bool // matched at a looser tolerance anywhere in the document
DiagnoseForm is the tool for a form that extracts nothing: AnchorInScope == false with
AnchorAnywhere == true means the scope is wrong, not the anchor.
type DoctypeSpec struct {
TitleWeight float64 // defaults to 0.4 when zero
HeadingWeight float64 // defaults to 0.3 when zero
ContentWeight float64 // defaults to 0.3 when zero
type ClassifyResult struct {
Matches map [ string ] float64 // document type to confidence
Method or function Returns (*Document) Classify(specs []DoctypeSpec) ClassifyResultScores explicit specs (*Document) ClassifyAs(docTypes ...string) ClassifyResultScores registered specs by name; an unknown name scores an empty spec RegisterDoctype(spec DoctypeSpec)Package function; appends a spec. Concurrency-safe RegisteredDoctypes() []DoctypeSpecDefaultDoctypes first, then registrations in orderResetDoctypes()Empties the caller registry (ClassifyResult) BestMatch() stringBestType(ClassifyResult) Confidence() float64BestConfidence(ClassifyResult) MatchesType(docType string, minConfidence float64) boolType scored at or above a threshold (ClassifyResult) Is(docType string) boolType is the best match
DefaultDoctypes ships six domain-neutral specs: invoice, receipt, contract, tax_form,
bank_statement, insurance. Vertical types are added with RegisterDoctype.
type SectionResult struct {
Heading string // Section heading text
Level int // Heading level (1=H1, 2=H2, ...)
Content string // All text content in the section
Subsections []SectionResult // Nested subsections
Page int // Page where the section starts
Box BoundingBox // Section bounding box
type OutlineEntryResult struct {
Text string // Heading text
Level int // Heading level
Box BoundingBox // Heading location
Children []OutlineEntryResult // Nested headings
type ColumnResult struct {
Index int // Column index (0-based, left to right)
Box BoundingBox // Column boundaries
Content string // Text content in the column
Method Returns (*SectionResult) Text() stringContent(*SectionResult) AllText() stringContent plus every subsection (*SectionResult) HasSubsections() bool / SubsectionCount() intNesting (*SectionResult) GetSubsection(heading string) *SectionResultChild by heading, case-insensitive (*SectionResult) FindSubsection(text string) *SectionResultChild by substring, recursive (*SectionResult) IsEmpty() boolNo content (*OutlineEntryResult) HasChildren() bool / ChildCount() intNesting (*OutlineEntryResult) GetChild(text string) *OutlineEntryResultChild by text, case-insensitive (*OutlineEntryResult) AllHeadings() []stringThis heading and every descendant (*ColumnResult) Text() string / IsEmpty() bool / Width() float64Column content and geometry