Cross-price elasticity calculator
Divide the percent change in demand for one good by the percent change in another good's price: demand up 20% after a 10% price rise gives an XED of 2, a strong substitute link. The sign and strength come labelled. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Quantity change pct
- 20
- Price change pct
- 10
- Elasticity
- 2
- Abs elasticity
- 2
- Relationship
- substitutes
- Strength
- elastic
Cross-price elasticity of demand measures how quantity demanded of one good responds when the price of a different good changes. Category managers, students, and pricing teams use the coefficient to tell substitutes from complements without guessing from anecdotes. This cross-price elasticity calculator accepts the percentage change in quantity of good X and the percentage change in price of good Y, divides the two, and returns the elasticity coefficient together with a substitutes-versus-complements label and a strength tag.
What cross-price elasticity measures and how the sign classifies goods
Cross-price elasticity of demand, often abbreviated XED or written as epsilon sub xy, is the ratio of the percentage change in quantity demanded of one good to the percentage change in price of a different good. When the price of tea rises and households buy more coffee, coffee and tea are substitutes and the coefficient is positive. When the price of printers rises and households buy fewer ink cartridges, printers and cartridges are complements and the coefficient is negative.
When quantity of X does not move at all, the goods are independent and XED is zero. The simple percent-change formula is XED equals percent change in Qx divided by percent change in Py. Because both numerator and denominator are already expressed as percents, twenty divided by ten is two, which is the same ratio as zero point two divided by zero point one.
The sign carries the relationship; the absolute value carries the strength. Absolute XED greater than one means a strong, elastic cross-price link; absolute XED between zero and one means a weak, inelastic link; absolute XED equal to one is unit cross-price elasticity. This calculator applies that identity only.
It does not estimate a demand system, run a regression, or apply the midpoint arc formula from raw levels: send the percentage changes you already measured or computed. A zero price change makes the ratio undefined, so the engine rejects it instead of returning infinity or a hollow not-a-number that graders might treat as success.
Where cross-price elasticity helps
Principles and intermediate microeconomics courses use a cross-price elasticity calculator so students can convert any pair of percentage changes into the textbook XED coefficient without flipping numerator and denominator or mixing own-price elasticity with the cross-price concept. Exam generators and LMS plugins need a deterministic oracle that rejects a zero price change instead of inventing infinity that a buggy grader might treat as success. Failed validation does not consume balance.
Keep requests small, pin the rounded elasticity and relationship fields in tests, and you get reproducible cross-price numbers for homework, LMS plugins, and edge workers without standing up a full demand-system estimation stack of your own.
What you can do with it
Classroom substitutes-versus-complements checks
Let students enter %ΔQx and %ΔPy and verify the XED coefficient, sign, and elastic/inelastic tag against textbook worked examples.
LMS and exam auto-grading
Mark cross-price elasticity items with a deterministic oracle that rejects a zero price change and never invents an infinite coefficient.
Category and pricing notebooks
Batch-classify SKU pairs as substitutes or complements from observed percent changes without spreadsheet formula drift.
FAQ
How is cross-price elasticity of demand calculated?
XED = (% change in quantity demanded of good X) / (% change in price of good Y).
What does a positive or negative XED mean?
Positive XED means substitutes: quantity of X rises when the price of Y rises. Negative XED means complements: quantity of X falls when the price of Y rises. XED of zero means independent goods.
Why is a zero price change rejected?
Dividing by a zero percent price change is undefined.
Is this the same as own-price elasticity or the inverse-elasticity markup rule?
No. Own-price elasticity uses the price of the same good. Inverse-elasticity markup starts from own-price |ε| and returns a monopoly markup.
How do I tell a strong cross-price link from a weak one?
Look at the size of the number and ignore its sign. Above one is a strong, elastic link; between zero and one is a weak, inelastic link; exactly one is unit cross-price elasticity.
Related tools
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/fin/cross-price-elasticity \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"quantity_change_pct":20,"price_change_pct":10}'const res = await fetch("https://api.kit.forhosting.com/fin/cross-price-elasticity", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"quantity_change_pct": 20,
"price_change_pct": 10
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/fin/cross-price-elasticity",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"quantity_change_pct": 20,
"price_change_pct": 10
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/fin/cross-price-elasticity", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"quantity_change_pct":20,"price_change_pct":10}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"quantity_change_pct":20,"price_change_pct":10}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/fin/cross-price-elasticity", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"quantity_change_pct": 20,
"price_change_pct": 10
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "fin.cross_price_elasticity",
"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.
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. |
Technical notes
A zero price change is rejected as invalid_input because the ratio is undefined when the denominator is zero.
Input contract, response fields, and validation rules
Send twenty for a twenty percent rise and negative twelve for a twelve percent drop. Zero quantity change is allowed and yields elasticity zero, meaning independent goods. Optional decimals is an integer from zero through twelve, default six, controlling half-up rounding on the echoed percentages and on elasticity. Example: quantity change twenty and price change ten yields elasticity two, substitutes, elastic. Quantity change negative thirty and price change fifteen yields elasticity negative two, complements, elastic. POST a JSON body with two required finite numbers: quantity_change_pct, the percentage change in quantity demanded of good X, and price_change_pct, the percentage change in the price of related good Y. Price change must be non-zero: a frozen price of Y leaves XED undefined, and that path fails with invalid_input and is not billed. Common aliases are accepted: qty_change_pct, percent_quantity, dqx, quantity_pct, or q_change for the quantity field; percent_price, dpy, price_pct, p_change, or py_change for the price field. Missing fields, empty strings, non-finite values, a zero price change, and out-of-range decimals fail with invalid_input naming the field. On success the body returns quantity_change_pct and price_change_pct rounded, elasticity as the coefficient %ΔQx over %ΔPy, abs_elasticity as its absolute value, relationship as substitutes, complements, or independent, strength as elastic, unit, inelastic, or none, a short interpretation sentence, and formula XED=%ΔQx/%ΔPy. Pair the coefficient with your own demand study if you need standard errors or a multi-good Almost Ideal Demand System; this endpoint divides two percentages and classifies the sign.
Where a cross-price elasticity API earns its keep
Category-management notebooks and retail pricing sandboxes often tabulate whether SKUs are substitutes or complements before they set bundle discounts or shelf adjacencies; pinning the arithmetic in a tiny parse API keeps spreadsheet drift out of the comparison column.
Technical questions
What does the cross-price elasticity calculator cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.