Publish your program data once, on your own domain
Write one structured file describing your programs, from tuition to start dates, deadlines, time to complete and schedules, host it on your .edu, and every affiliate, comparison site and AI assistant that subscribes gets your official numbers. When you change a price, a date or a program's status, they're told the same day.
The OLF vocabulary, the file names and Open Learning Feed are proposals. The validator works; registration is not open yet. Examples use Example University, a fictional school; every figure for it is invented.
What you control
- What is served. Publish only the programs and prices you choose. Anything you leave out stays out.
- How it updates. Produce the file from your own systems, on your own schedule. Change it whenever your pages change.
- Accuracy. Every price points to the page on your site where it appears, with the date you confirmed it.
- Leaving. Delete olf.json, and Open Learning Feed will mark your feed unreachable after 48 hours and remove your listing after 30 days.
The one file
Your feed, at the root of your site
Your programs, prices, schedules and sources in one JSON file that uses schema.org's vocabulary, with the OLF extension. Keep the "@context" line at the top: it is what makes the file schema.org (technically, JSON-LD) rather than arbitrary JSON. Every subscriber looks for it at the same address on every school's site, so there's nothing else to publish. Its place on your domain is what proves it's official.
- Who to contact goes inside the file, as a schema.org
contactPointon thepublisher. - Hosted somewhere else? If a vendor or CDN serves your feed, redirect
/olf.jsonto it. Subscribers follow the redirect. - Already published
/olf.jsonld? That earlier name still works. Subscribers check/olf.jsonfirst, then/olf.jsonld. - Separate feeds per college? Keep one feed at the root and list the others in it with
olf:includesFeed.
Already using schema.org?
Many schools already add schema.org markup to program pages for search engines. That markup is the start of your feed. The feed uses the same EducationalOccupationalProgram object, follows schema.org's structure and rules, and adds olf properties only for what schema.org can't express.
<script type="application/ld+json">
{
"@context": ["https://schema.org", "https://olfeed.org/vocab/context.jsonld"],
"@type": "EducationalOccupationalProgram",
"name": "Master of Business Administration",
"url": "https://www.example.edu/programs/mba/",
"provider": { "@type": "CollegeOrUniversity", "name": "Example University" },
"educationalProgramMode": "online",
"numberOfCredits": 36,
"timeToComplete": "P18M",
"startDate": "2027-01-11",
"olf:programStatus": "olf:AcceptingApplications",
"olf:admissionTestPolicy": "olf:TestNotRequired",
"olf:completionTime": [ … ],
"olf:classSchedule": [ … ],
"offers": { "@type": "Offer", "priceSpecification": [ … ] }
}
</script>{
"@context": "https://olfeed.org/vocab/context.jsonld",
"@type": "olf:InstitutionProgramFeed",
"olf:ownerDomain": "https://www.example.edu",
"olf:feedVersion": "2026-10-01",
"publisher": { "contactPoint": { "email": "feeds@example.edu" } },
"dataFeedElement": [
{ "@type": "DataFeedItem", "dateModified": "2026-10-01",
"item": { /* the same program object as on the page */ } }
]
}- One object, two places. The program object on the page and the one in the feed should be identical. Produce both from the same source so they can't drift.
- Nothing breaks for schema.org-only tools. Search engines and other tools that know only schema.org skip the
olfproperties and still read everything else. - We follow schema.org's lead. The extension tracks each schema.org release. When schema.org adds a term that covers one of ours, we switch to theirs. See Staying current.
What doesn't go in the feed
salaryUponCompletion, trainingSalary and occupationalCategory.Step by step
List your public sources
Find the pages where each value already appears: your tuition and fees page, each program page and your catalog. Every price in the feed points to one of them, so start from what you already publish. A figure you report from a federal or audited source can point to that source instead.
Write the feed
Start from the worked example or the skeleton below. Add one
DataFeedItemper program. Fill the required fields first, then add recommended ones.{ "@context": { "@vocab": "https://schema.org/", "olf": "https://olfeed.org/ns#" }, "@type": "olf:InstitutionProgramFeed", "olf:ownerDomain": "https://www.your-school.edu", "olf:feedVersion": "2026-10-01", "publisher": { "@type": "CollegeOrUniversity", "name": "Your School", "contactPoint": { "@type": "ContactPoint", "contactType": "Program data", "email": "feeds@your-school.edu" } }, "dataFeedElement": [ { "@type": "DataFeedItem", "dateModified": "2026-10-01", "item": { /* one EducationalOccupationalProgram */ } } ] }Put it at the root of your site
Serve the file at
https://your-domain/olf.jsonwith these headers. The CORS header lets browser-based tools read it directly.Content-Type: application/json; charset=utf-8 Access-Control-Allow-Origin: * Cache-Control: max-age=3600
Validate
Paste the feed into the validator, or add the JSON Schema check to your build so a broken feed never ships.
Register
Submit your domain to Open Learning Feed. It fetches
/olf.json, validates it and starts notifying subscribers. Registration isn't open yet.
Required fields
A feed with every required field is valid and gets listed. Recommended fields make your listings far more useful to students. Paths are relative to each program unless marked.
| Field | Defined by | Tier | What to put there |
|---|---|---|---|
@context (feed) | schema.org + olf | Required | The shared context file, or schema.org as @vocab plus "olf": "https://olfeed.org/ns#" |
@type (feed) | olf | Required | olf:InstitutionProgramFeed |
olf:ownerDomain (feed) | olf | Required | Your domain with https, such as https://www.your-school.edu |
olf:feedVersion (feed) | olf | Required | Date of this version, YYYY-MM-DD. Change it every time you publish. |
dataFeedElement[] (feed) | schema.org | Required | One DataFeedItem per program, each with dateModified and the program as item |
publisher.contactPoint (feed) | schema.org | Recommended | Who to contact about the feed: an email or a page |
@type | schema.org | Required | EducationalOccupationalProgram |
name | schema.org | Required | Program name exactly as on your program page |
olf:programStatus | olf | Required | olf:AcceptingApplications, olf:Launching, olf:Paused, olf:TeachOut or olf:Discontinued |
educationalProgramMode | schema.org | Required | online, onsite or hybrid |
educationalCredentialAwarded.educationalLevel | schema.org | Required | certificate, associate, bachelor, master or doctoral |
offers.priceSpecification[] | schema.org + olf | Required | At least one current olf:TuitionPriceSpecification with price, priceCurrency and olf:tuitionBasis |
olf:provenance on every price | olf | Required | olf:sourceUrl, an https page on your own domain (or the source's page for a federal or audited figure), and olf:verifiedDate |
olf:eligibleAudience | olf | When needed | Who a price applies to. Required whenever more than one current tuition rate applies: only one may go without an audience. |
olf:TuitionDiscount | olf | Recommended if you offer them | Grants and discounts, with a percent or amount, the audience and whether they combine |
numberOfCredits | schema.org | Recommended | Credits to complete |
olf:transferCreditPolicy | olf | Recommended | Maximum transfer credits and accepted sources |
provider.hasCertification | schema.org | Recommended | Your accreditor |
startDate, applicationDeadline | schema.org | Recommended | The next start and its deadline. Update them after each start passes. |
olf:admissionTestPolicy | olf | Recommended | Whether a GMAT, GRE, SAT or ACT score is required, optional or waivable |
timeToComplete, olf:completionTime | schema.org + olf | Recommended | Typical time to finish, full time and part time, and with common transfer credit. Students ask this first. |
olf:classSchedule | olf | Recommended | When classes meet: daytime, evenings, weekends, live online sessions or self-paced online, with days, times and time zone |
olf:focusArea | olf | Optional | Concentrations, specializations or tracks, each with a name, credits and olf:focusAreaType saying which word you use |
programType (CIP code) | schema.org | Optional | A DefinedTerm from CIP 2020 |
Worked example
The full feed of Example University, a fictional online school, with two programs: a bachelor's in cybersecurity and an MBA. Every price points to a page on the school's own domain, last year's rates stay in the file with their end dates as price history, and the feed passes the validator.
Example: an MBA
Graduate programs carry details a bachelor's listing doesn't. This MBA from the same fictional school shows how each one is written. Get it on its own at /examples/example-mba.json or from the API at /v1/programs/example.edu/mba.
| Detail | Field | In this example |
|---|---|---|
| Time to complete | timeToComplete, olf:completionTime | 18 months full time (12 at the fastest), 36 months part time, 15 months with 9 transfer credits |
| Class days and times | olf:classSchedule | Self-paced coursework, plus optional live sessions Tuesday and Thursday, 7:00 to 8:30 pm Eastern |
| Term length | termDuration, termsPerYear | 8-week terms, 6 a year |
| Next start and deadline | startDate, applicationDeadline | Starts Jan 11, 2027; apply by Dec 14, 2026 |
| Test policy | olf:admissionTestPolicy (new) | No GMAT or GRE required |
| Admission requirements | programPrerequisites | Bachelor's degree, plus a 3.0 GPA or two years of experience |
| Specializations | olf:focusArea with olf:focusAreaType | Finance, Marketing Analytics, Healthcare Management, Cybersecurity Leadership; 12 credits each. The school calls them specializations, so subscribers will too. |
| Program accreditation | hasCertification on the program | Example Business Accreditation Council, separate from the school's institutional accreditor |
| Field of study | programType (CIP code) | CIP 52.0201, Business Administration and Management, General |
| Fees kept apart from tuition | priceComponentType | $75 technology fee per course, alongside $480 tuition per credit |
| Employer discount | olf:TuitionDiscount with olf:EmployerPartner | 15% for employees of partner companies, with the proof required |
The new terms used here, including olf:focusArea, olf:completionTime, olf:classSchedule and olf:admissionTestPolicy, are defined in the specification. Program-level hasCertification is one of the widenings proposed to schema.org.
Common pricing patterns
These snippets use another fictional school, Sample State College, to show patterns the worked example doesn't cover. Each one goes inside a program's offers.priceSpecification list.
In-state and out-of-state tuition
[
{ "@type": "olf:TuitionPriceSpecification", "name": "In-state",
"price": 310, "priceCurrency": "USD", "olf:tuitionBasis": "olf:PerCreditHour",
"olf:eligibleAudience": { "olf:eligibilityCategory": ["olf:InStateResident"] },
"olf:provenance": { "olf:sourceUrl": "https://www.sample-state.example/tuition", "olf:verifiedDate": "2026-09-01" } },
{ "@type": "olf:TuitionPriceSpecification", "name": "Out-of-state",
"price": 760, "priceCurrency": "USD", "olf:tuitionBasis": "olf:PerCreditHour",
"olf:eligibleAudience": { "olf:eligibilityCategory": ["olf:OutOfStateResident"] },
"olf:provenance": { "olf:sourceUrl": "https://www.sample-state.example/tuition", "olf:verifiedDate": "2026-09-01" } }
]Evening and weekend classes
"olf:classSchedule": [
{ "@type": "Schedule", "olf:scheduleType": "olf:Evening",
"byDay": ["Monday", "Wednesday"], "startTime": "18:00", "endTime": "21:00",
"scheduleTimezone": "America/Chicago", "repeatFrequency": "P1W" },
{ "@type": "Schedule", "olf:scheduleType": "olf:Weekend",
"byDay": ["Saturday"], "startTime": "09:00", "endTime": "16:00",
"scheduleTimezone": "America/Chicago", "repeatFrequency": "P2W",
"description": "Every other Saturday" }
]List one Schedule per option a student can choose. Self-paced online coursework uses olf:AsynchronousOnline with no days or times.
Full-time, part-time and transfer timelines
"timeToComplete": "P24M", "olf:completionTime": [ { "olf:enrollmentIntensity": "olf:FullTime", "olf:typicalDuration": "P24M", "olf:minimumDuration": "P20M" }, { "olf:enrollmentIntensity": "olf:PartTime", "olf:typicalDuration": "P42M" }, { "olf:enrollmentIntensity": "olf:FullTime", "olf:typicalDuration": "P12M", "olf:assumedTransferCredits": 30 } ]
Durations use ISO 8601: P18M is 18 months, P2Y is two years, P16W is 16 weeks.
A price increase on a known date, keeping history
[
{ "@type": "olf:TuitionPriceSpecification", "name": "In-state",
"price": 310, "priceCurrency": "USD", "olf:tuitionBasis": "olf:PerCreditHour",
"validThrough": "2026-12-31", "olf:eligibleAudience": { /* in-state */ }, "olf:provenance": { /* … */ } },
{ "@type": "olf:TuitionPriceSpecification", "name": "In-state",
"price": 325, "priceCurrency": "USD", "olf:tuitionBasis": "olf:PerCreditHour",
"validFrom": "2027-01-01", "olf:eligibleAudience": { /* in-state */ }, "olf:provenance": { /* … */ } }
]Publishing a future rate early lets subscribers switch on the right day. Keep expired rates with their validThrough date. They become your price history.
Validator
Paste your feed, or load an example. The validator applies the required-field rules plus checks a schema file can't do: sources for values you publish must be on your own domain, verified dates can't be in the future, and each program needs at least one current price.
JSON Schema for your build
Add the structural check to the same pipeline that publishes your website, so a feed with a missing field never goes live. The schema covers field names, types and allowed values. Run the validator above for the date and domain checks.
curl -O https://olfeed.org/schema/olf-1.0.json npx ajv-cli validate --spec=draft2020 -s olf-1.0.json -d olf.json
- name: Validate program feed
run: |
curl -sO https://olfeed.org/schema/olf-1.0.json
npx --yes ajv-cli validate --spec=draft2020 -s olf-1.0.json -d public/olf.json
Schema file: /schema/olf-1.0.json (draft).
Keeping it current
The feed is only as good as its last update. The simplest rule: change the feed in the same release that changes the page.
- Produce it from the same source as your pages. If your tuition page comes from a CMS field or a catalog system, output the feed from that same field. Then the two can't drift apart.
- Change
olf:feedVersionon every publish. Open Learning Feed compares versions to decide what changed and whom to notify. - Update
olf:verifiedDatewhen someone confirms a value, even if it didn't change. Values unconfirmed for a year get flagged. - Mark closures with status, not deletion. Set
olf:TeachOutorolf:Discontinuedso affiliates take the program down. A program that simply disappears looks like an error.
Your dashboard
Once registration opens, the dashboard is planned to show who reads your feed and whether they keep up. This mockup uses illustrative data.
| Subscriber | Connection | Last pulled | Showing |
|---|---|---|---|
| Affiliate site A | Notifications | 2 minutes ago | Current |
| Comparison site B | API | 1 hour ago | Current |
| Benefits site E | Embed | Live on page load | Current |
| AI assistant F | MCP | Live per query | Current |
| Ranking site C | API | 19 days ago | 1 version behind |
| Directory site D | Not connected | Never | Scraped 2022 rates |
Subscriber names are invented for illustration.
Questions
Do we have to publish every program?
No. Publish the programs you want listed. Aggregators that use the feed will show only what you include.
Who writes the file?
Your team or an agency you hire. A converter that drafts a feed from your existing exports is planned, but you review the result and host the file yourself, so the data always comes from you.
What if our feed has an error?
Open Learning Feed is designed to keep serving your last valid version, email your contact and show the problem in your dashboard, so nothing broken reaches subscribers.
Can we explain a federal price figure we think is misleading?
Yes, for prices. Publish the federal figure as a price whose provenance has olf:sourceType olf:FederalReported and the federal page as its source, and add an olf:contextNote with your explanation. Subscribers show both, so you add context without replacing the official number. Version 1.0 has no place for other federal figures, such as outcome rates.
What does it cost?
Publishing and listing are planned to be free. The dashboard and the stale-data audit would be paid. Pricing isn't set yet.