Fifty-five fields per project, measured on 718 projects across 12 subcategories and 8 countries. Coverage here is reported as how often a field carries useful information, which is not the same as how often the key exists — and on this dataset the difference is large.
How to read this reference
A percentage is useful coverage. `client_rating` is present on 100% of rows and reported at 19.4%, because 80.5% of its values encode “no history”. That convention is the whole reason this reference is worth reading rather than skimming.
Identity and description
| Field | Useful | Notes |
|---|---|---|
slug | 100% | The join key across snapshots. |
url | 100% | Canonical project URL. |
title | 100% | As published, in the requested locale. |
description_text | 100% | Posting-form block removed, because it comes out as fields. |
description_html | 100% | Workana's original, untouched. |
description_has_contact | 100% | Flags descriptions where the client published contact details. |
locale | 100% | Which language Workana rendered. Decides how the budget parses. |
description_text deliberately no longer repeats the posting-form block, because that metadata comes out as its own fields — leaving it in the text too would inflate the largest field in the dataset for no gain. description_html keeps the original for anyone who wants it.
Budget
Eight fields, and they have to be read together: budget_raw, budget_min (75.0%), budget_max (95.6%), budget_currency, budget_unit, budget_type, budget_open_ended and is_hourly (11.7% true).
The 75.0% on budget_min is not a parse failure — a quarter of budgets have no lower bound. Group by budget_type before comparing anything.
Client signals
client_name_masked (100%, masked by Workana itself), client_country_code and client_country_name (100%), client_rating (19.4% useful), client_has_rating, client_rating_raw, client_payment_verified (18.9% true) and client_plan (0.4% — too rare to build on).
Timing and competition
total_bids with total_bids_raw, posted_at with posted_at_raw, posted_at_approximate and posted_age_hours, plus deadline_days (1.9%) and last_client_message_raw (51.7%).
posted_age_hours is the field that makes total_bids usable, because competition arrives within hours and a raw count without an age is not comparable across projects.
Taxonomy and skills
category and category_name at 100%, subcategory and subcategory_name at 100%, skills and skill_slugs at 98.6%, plus matched_query and matched_skill_slug recording which query produced the row.
category is always filled even when you query by subcategory or by skill: the parent-child relationship comes from Workana's own taxonomy rather than from a lookup table that could drift.
The posting form's answers
Workana appends the client's answers to its posting form at the end of every description — structured data hiding inside prose. The Actor extracts it:
| Field | Present | Notes |
|---|---|---|
project_scope | 68% | "Create a new custom site", "Small bug or change"… |
project_size | 30.5% | Small / Medium / Large. |
engagement_type, required_availability, time_required | varies | By subcategory. |
client_needs, client_currently_has, required_platforms | varies | By subcategory. |
extra_attributes | varies | The subcategory-specific tail, with original labels. |
extra_attributes is by design, not a gap. Workana asks questions specific to each subcategory — logo type, app type, payment processor — and that tail is endless. The cross-cutting questions get their own columns; the rest travels here with its original label, so nothing is lost and the schema does not grow columns that are almost always empty.
Fields that are deliberately absent
isUrgent, isCompany and isInvite were false in all 718 measured projects — an anonymous visitor never sees them set — and shortDescription was empty throughout.
A column with one constant value is not data, so they are not in the output. Including them would add four fields to every row and a plausible-looking filter that can only ever return nothing.


