Skip to main content

Overview

This guide walks you through a complete Cardinal workflow using a real example. You’ll initialize settings, prepare OCDS data, and calculate procurement indicators.
Before you begin: Make sure you have Cardinal installed on your system.

Prerequisites

  • Cardinal installed via Cargo or pip
  • OCDS data in line-delimited JSON format (compiled releases)
  • Basic familiarity with the command line
Don’t have OCDS data yet? Download sample data from the OCP Data Registry or use the examples in this guide.

Complete Workflow

Cardinal’s workflow consists of three main steps: initialize settings, prepare data, and calculate indicators.

Step 1: Initialize Settings

Create a default configuration file that enables all indicators and documents all available options:
ocdscardinal init settings.ini
Settings written to settings.ini.
This generates a settings.ini file with default values and extensive comments explaining each option.
You can preview settings without creating a file by using - as the filename:
ocdscardinal init -
This outputs the settings to your terminal:
; currency = USD
; no_price_comparison_procurement_methods = Random Selection
; price_comparison_procurement_methods = Reverse Auction

[output]
; info_currency_mismatches = true

; `prepare` command
;
; Read the documentation at:
; https://cardinal.readthedocs.io/en/latest/cli/prepare.html

[defaults]
; currency = USD
; item_classification_scheme = UNSPSC
; bid_status = valid
; award_status = active
; party_roles = true

[redactions]
; amount = 0
; organization_id = placeholder

; ... (additional configuration sections)

[R003]
; threshold = 15
; procurement_methods = open|selective|limited

[R018]
; procurement_methods = open|selective

[R024]
; threshold = 0.05

; ... (more indicator configurations)

Step 2: Prepare Your Data

The prepare command corrects quality issues in your OCDS data and reports problems that could affect indicator calculations.
1

Run the prepare command

Process your input data, writing corrected data to one file and quality issues to another:
ocdscardinal prepare input.jsonl \
  --settings settings.ini \
  --output prepared.jsonl \
  --errors issues.csv
Replace input.jsonl with your OCDS data file.
  • input.jsonl: Your OCDS compiled releases (one JSON object per line)
  • --settings settings.ini: Configuration file from step 1
  • --output prepared.jsonl: Where to write corrected data
  • --errors issues.csv: Where to write quality issue reports
2

Review quality issues

Open issues.csv to see reported quality issues. The CSV has these columns:
ColumnDescription
lineLine number in the input file
ocidOCID of the contracting process
pathJSON path to the problematic field
array indexesIndex position if the field is in an array
incorrect valueThe problematic value (blank if not set)
error descriptionType of issue: not set, invalid, or is zero
Example issue:
line,ocid,path,array indexes,incorrect value,error description
1,ocds-213czf-1,/bids/details[]/status,0,,not set
This indicates that bid #0 in contracting process ocds-213czf-1 is missing a status field.
3

Configure data corrections

Edit settings.ini to fix quality issues automatically. For example, if bids are missing status values, add:
[defaults]
bid_status = valid
Common configurations:
[defaults]
currency = USD
[defaults]
item_classification_scheme = UNSPSC
[redactions]
amount = 0|99999999
[modifications]
prefix_tenderer_or_supplier_id = DO-RPE-
[codelists.bid_status]
Qualified = valid
Disqualified = disqualified
4

Re-run and iterate

Run the prepare command again with your updated settings:
ocdscardinal prepare input.jsonl \
  --settings settings.ini \
  --output prepared.jsonl \
  --errors issues.csv
Review issues.csv again. Repeat this process until you’re satisfied with the data quality.
Most quality issues are repetitive and can be fixed with a single configuration change. For example, if 1,000 bids are missing statuses, adding bid_status = valid fixes all of them at once.

Step 3: Calculate Indicators

Run red flag analysis on your prepared data:
ocdscardinal indicators --settings settings.ini prepared.jsonl > results.json
Additional flags you can use:
ocdscardinal indicators \
  --settings settings.ini \
  --count \
  --map \
  prepared.jsonl > results.json
  • --count: Print the number of results per group to stderr
  • --map: Include mappings from contracting processes to organizations
  • --no-meta: Exclude statistical metadata from results

Step 4: Analyze Results

Open results.json to view your indicator results.
{
  "OCID": {
    "ocds-213czf-1": {
      "R036": 1.0,
      "R028": 1.0
    },
    "ocds-213czf-2": {
      "R018": 1.0,
      "R030": 1.0
    }
  },
  "Buyer": {
    "DO-UC-55216": {
      "R038": 0.85
    }
  },
  "Tenderer": {
    "DO-RPE-1422": {
      "R025": 0.12,
      "R048": 2.5
    }
  },
  "Meta": {
    "R024": {
      "q1": 66.67,
      "q3": 100.0,
      "lower_fence": 16.67
    },
    "R025": {
      "q1": 0.5,
      "q3": 1.0,
      "lower_fence": 0.0
    }
  }
}

Understanding the Output

Results are organized by group (OCID, Buyer, ProcuringEntity, Tenderer) and identifier:
Results for individual contracting processes, keyed by /ocid.Example: "ocds-213czf-1" triggered indicators R036 and R028.
  • R036: Lowest bid disqualified (value: 1.0 = true)
  • R028: Identical bid prices (value: 1.0 = true)
Results aggregated by buyer organizations, keyed by /buyer/id.Example: Buyer "DO-UC-55216" has a high rate of disqualified bids (R038: 0.85).
Results aggregated by procuring entities, keyed by /tender/procuringEntity/id.
Results aggregated by tenderers (bidders), keyed by /bids/details[]/tenderers[]/id.Example: Tenderer "DO-RPE-1422" has:
  • R025: Low win rate (0.12 = winning bid rate is a low outlier)
  • R048: High variety of items supplied (2.5 = heterogeneous supplier)
Statistical information about quartiles and fences used for outlier detection:
"R024": {
  "q1": 66.67,      // First quartile
  "q3": 100.0,      // Third quartile
  "lower_fence": 16.67  // Outlier threshold
}
These values help you understand how indicators determined outliers.

Indicator Codes

Each code represents a specific red flag:
CodeRed FlagDescription
R003Short submission periodSubmission period is too short
R018Single bid receivedOnly one tenderer submitted a bid
R024Price close to winning bidSecond-lowest bid is suspiciously close to winner
R025Excessive unsuccessful bidsTenderer has low win rate (outlier)
R028Identical bid pricesMultiple tenderers submitted same price
R030Late bid wonWinning bid received after deadline
R035All except winner disqualifiedOnly winner’s bids were valid
R036Lowest bid disqualifiedLowest bid rejected despite price-only criterion
R038Excessive disqualified bidsHigh disqualification rate (outlier)
R048Heterogeneous supplierTenderer supplies unusually diverse items
R058Heavily discounted bidWinner’s price is much lower than competitors
Learn more about each indicator in the Indicators documentation.

Real-World Example

Let’s walk through a concrete example using sample data.

Sample Data

Create a file called example.jsonl with this OCDS compiled release:
{"ocid":"ocds-213czf-1","buyer":{"id":"DO-UC-001","name":"Ministry of Education"},"tender":{"id":"T-001","title":"Office Supplies","status":"complete","procuringEntity":{"id":"DO-UC-001"},"procurementMethod":"open","tenderPeriod":{"startDate":"2023-01-01T00:00:00Z","endDate":"2023-01-08T00:00:00Z"},"value":{"amount":100000,"currency":"USD"}},"bids":{"details":[{"id":"BID-001","status":"valid","tenderers":[{"id":"SUP-001","name":"Supplier A"}],"value":{"amount":95000,"currency":"USD"}},{"id":"BID-002","status":"disqualified","tenderers":[{"id":"SUP-002","name":"Supplier B"}],"value":{"amount":92000,"currency":"USD"}},{"id":"BID-003","status":"valid","tenderers":[{"id":"SUP-003","name":"Supplier C"}],"value":{"amount":98000,"currency":"USD"}}]},"awards":[{"id":"AWD-001","status":"active","suppliers":[{"id":"SUP-001","name":"Supplier A"}],"value":{"amount":95000,"currency":"USD"}}]}
This represents a procurement where the lowest bid (SUP-002 at 92,000)wasdisqualified,andthesecondlowestbid(SUP001at92,000) was disqualified, and the second-lowest bid (SUP-001 at 95,000) won.

Run the Analysis

1

Initialize settings

ocdscardinal init settings.ini
2

Prepare data

ocdscardinal prepare example.jsonl \
  --settings settings.ini \
  --output prepared.jsonl \
  --errors issues.csv
3

Calculate indicators

ocdscardinal indicators --settings settings.ini \
  prepared.jsonl > results.json
4

View results

cat results.json | jq .
You should see results indicating that R036 (Lowest bid disqualified) was triggered for this contracting process.

Common Workflows

To test a single indicator, disable all others in your settings file by commenting out their sections:
; [R003]
; [R018]
[R036]  ; Only R036 is enabled
; [R038]
Some procedures shouldn’t be analyzed (e.g., emergency procurements). Exclude them:
[exclusions]
procurement_method_details = Emergency|Direct Award|Random Selection
If you’re getting too many false positives, increase indicator thresholds:
[R003]
threshold = 20  ; Increase from default 15 days

[R024]
threshold = 0.10  ; Increase from default 0.05 (5%)
Cardinal handles large files efficiently, but you can monitor progress:
# Increase verbosity to see progress
ocdscardinal indicators -vv --settings settings.ini \
  large_dataset.jsonl > results.json
Use -v for warnings, -vv for info, -vvv for debug output.

Troubleshooting

Possible causes:
  1. Settings file missing indicator sections: Check that indicators are enabled in settings.ini
  2. Data quality issues: Review issues.csv - missing required fields prevent calculations
  3. All data excluded: Check your [exclusions] configuration
  4. Currency mismatches: Cardinal excludes processes with non-primary currencies
Run with increased verbosity to see more details:
ocdscardinal indicators -vv --settings settings.ini prepared.jsonl
  1. Adjust thresholds in your settings file for specific indicators
  2. Add exclusions for procurement methods that shouldn’t be analyzed
  3. Configure price comparison methods to exclude inappropriate procedures:
    no_price_comparison_procurement_methods = Framework Agreement|Reverse Auction
    
This is normal! Most issues are repetitive:
  1. Sort the CSV by the path column to group similar issues
  2. Add configuration to fix entire categories at once
  3. Focus on not set errors first - these prevent indicator calculations
  4. Iterate - run prepare → review → configure → repeat

Next Steps

Prepare Command

Deep dive into data preparation and quality corrections

Indicators Command

Learn about all indicator calculation options

Settings Configuration

Master Cardinal’s configuration system

Red Flags Reference

Understand each indicator’s methodology