Giffen Good Check Calculator from Price and Quantity Data
A Giffen good is an unusual case in which quantity demanded rises as the good's own price rises, contrary to the usual downward-sloping demand relationship.
Run — free
This calculator checks observed price and quantity pairs for that positive response by fitting a straight-line demand relationship with ordinary least squares. It reports the slope, correlation, fit quality, and the direction of adjacent changes, then gives a clear classification. The result is a diagnostic for your dataset, not proof that price alone caused the observed quantities.
Prepare observations that support a meaningful comparison
Enter at least two observations for the same good, recording a positive own price and a nonnegative quantity demanded in each row. More observations across several distinct prices produce a more informative check than a single before-and-after comparison. Try to use the same market, time scale, product definition, and quantity unit throughout. The method assumes that rows are reasonably comparable, so mixing weekly quantities with monthly quantities or package prices with per-unit prices will distort the result. Other demand influences matter as well. Income, population, seasonality, promotions, product quality, rationing, expectations, and prices of substitutes or complements can all move quantity while price changes. If those factors vary sharply across rows, a positive fitted slope may reflect confounding rather than Giffen behavior. Repeated observations at the same price are accepted and contribute to the regression, but the dataset must contain at least two distinct prices. Use the optional slope tolerance when tiny positive movements should be treated as practically negligible because of measurement resolution or sampling noise. The tolerance uses quantity units per one price unit, so choose it in the same units as your data rather than as a percentage.
Understand how the check reaches its conclusion
The calculator fits quantity demanded as a linear function of own price using ordinary least squares. Its slope estimates the average change in quantity associated with a one-unit increase in price across the supplied observations. The result is classified as behaving like a Giffen good when that slope is strictly greater than the chosen slope tolerance. A zero or negative slope does not pass. The output includes the intercept for reproducing the fitted line, covariance and correlation for describing direction and strength, and R-squared for showing how much of the observed quantity variation the simple line accounts for. Correlation ranges from negative one to positive one, while R-squared ranges from zero to one. These statistics are descriptive, not a significance test. The calculator also sorts observations by price and counts adjacent pairs whose quantities rise, fall, or remain unchanged. Those counts make mixed patterns visible, but they do not replace the regression classification. Equal-price neighbors are excluded from adjacent comparisons because they contain no own-price change. All reported decimals are rounded deterministically, and the original rows are never reordered or modified outside the calculation.
Interpret a positive result with economic caution
A positive result means the fitted relationship in the submitted sample has quantity rising with own price by more than the tolerance. That is consistent with the defining observable pattern of Giffen behavior, but it is not sufficient to establish that the good is truly Giffen. Economic identification requires separating the substitution effect from the income effect and controlling for competing explanations. Classical Giffen behavior is associated with an inferior good for which the negative real-income effect of a price increase is strong enough to outweigh substitution away from the now more expensive good. Observational records rarely isolate that mechanism on their own. Review the correlation and R-squared alongside the classification: a slightly positive slope with weak fit and conflicting adjacent changes deserves much less confidence than a stable pattern collected under controlled conditions. Consider segmenting data by household income, location, product grade, or period, and use econometric controls or an experimental design when the decision is consequential. A negative result only says this dataset does not show a positive response above the threshold; it does not prove that Giffen behavior is impossible in every population or price range. The browser check is free, while an API request is billed at $0.002.
What you can do with it
Screen household consumption data
Check whether purchases of a staple rise with its observed price before planning a deeper demand study.
Audit a classroom dataset
Reproduce the fitted slope and compare the empirical pattern with the theoretical definition of a Giffen good.
Triage market research
Identify product and segment datasets with positive own-price patterns that merit controlled econometric analysis.
FAQ
Does a positive result prove the good is Giffen?
No. It shows a positive fitted own-price response in the supplied observations. Causal evidence and controls are needed to rule out income changes, seasonality, promotions, and other confounders.
Why are at least two distinct prices required?
A price slope cannot be estimated when every observation has the same price, even if quantities differ.
What does slope tolerance do?
It sets the minimum positive quantity-per-price slope that the fitted response must exceed, which can prevent negligible positive values from triggering the classification.
Are repeated prices allowed?
Yes. Repeated prices contribute to the regression, although equal-price neighbors are not counted as comparable adjacent price changes.
What does the API request cost?
Each API request costs $0.002. The calculation can also run locally in the browser without sending the observations to the API.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/econ/giffen-good-check \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"observations":[{"price":2,"quantity":10},{"price":3,"quantity":13},{"price":4,"quantity":15},{"price":5,"quantity":19}]}'const res = await fetch("https://api.kit.forhosting.com/econ/giffen-good-check", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"observations": [
{
"price": 2,
"quantity": 10
},
{
"price": 3,
"quantity": 13
},
{
"price": 4,
"quantity": 15
},
{
"price": 5,
"quantity": 19
}
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/econ/giffen-good-check",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"observations": [
{
"price": 2,
"quantity": 10
},
{
"price": 3,
"quantity": 13
},
{
"price": 4,
"quantity": 15
},
{
"price": 5,
"quantity": 19
}
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/econ/giffen-good-check", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"observations":[{"price":2,"quantity":10},{"price":3,"quantity":13},{"price":4,"quantity":15},{"price":5,"quantity":19}]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"observations":[{"price":2,"quantity":10},{"price":3,"quantity":13},{"price":4,"quantity":15},{"price":5,"quantity":19}]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/econ/giffen-good-check", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"observations": [
{
"price": 2,
"quantity": 10
},
{
"price": 3,
"quantity": 13
},
{
"price": 4,
"quantity": 15
},
{
"price": 5,
"quantity": 19
}
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "econ.giffen_good_check",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_items | 10000 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |