Confidence Interval for the Difference of Proportions Calculator
This confidence interval for the difference of proportions calculator estimates how far apart two population proportions may be, using observed proportions, independent sample sizes, and a selected confidence level.
Run — free
It applies the familiar unpooled normal approximation and reports the observed difference as first proportion minus second proportion, together with its standard error, margin of error, critical value, and interval bounds. Use it for a transparent comparison when each sample represents a separate group and the normal approximation is reasonable.
Enter proportions and sample sizes in the right form
Provide each observed proportion as a decimal from zero through one, such as 0.62 rather than 62 for 62 percent. Pair every proportion with the total number of independent observations used to calculate it. The first and second labels matter because the estimate is calculated as proportion one minus proportion two: a positive result means the first observed rate is higher, while a negative result means it is lower. Sample sizes must be whole numbers of at least one. Also enter the two-sided confidence level as a decimal strictly between zero and one; 0.95 requests a 95 percent interval. The calculator accepts proportions at the endpoints zero and one, although the ordinary normal approximation can perform poorly there. If your raw data consist of event counts, divide each event count by its corresponding total before entering it and retain enough precision to avoid unnecessary rounding. Both samples should measure the same binary outcome under compatible definitions. They should also be independent; paired before-and-after observations require a method designed for matched data rather than this independent-samples formula.
Follow the unpooled normal calculation
The observed difference is p one minus p two. Its estimated standard error is the square root of two terms added together: p one times one minus p one divided by n one, plus p two times one minus p two divided by n two. This is called an unpooled standard error because each sample supplies its own variance estimate. The requested confidence level determines a two-sided standard normal critical value. Multiplying that critical value by the standard error gives the margin of error, which is subtracted from and added to the observed difference to form the lower and upper bounds. The endpoint calculations are not clipped to minus one and one. Although a true difference between proportions must lie in that range, unmodified Wald limits can extend beyond it, and preserving those values makes the method explicit rather than silently substituting a different interval. The inverse-normal calculation uses a deterministic rational approximation, so identical inputs produce identical results without random simulation, network access, or time-dependent behavior. Returned intermediate values make the result easy to audit or reproduce in another statistical package.
Interpret the interval and assess whether Wald is suitable
Interpret the interval as uncertainty around the population difference, not as a probability that a fixed parameter lies between the reported endpoints. Under repeated sampling and the model assumptions, a procedure requested at 95 percent confidence would cover the true difference about 95 percent of the time. An interval containing zero indicates that no difference remains clearly separated from zero at the corresponding two-sided significance level; it does not prove that the groups are identical or that a practically meaningful effect is absent. The normal approximation is most credible when each sample contains enough observed events and non-events. A common diagnostic is to check that n times p and n times one minus p are not small in either group. Very small samples, rare events, or proportions close to zero or one can produce misleadingly narrow or degenerate Wald intervals; an exact, score, or Newcombe-style method may then be preferable. Independence, representative sampling, consistent outcome definitions, and freedom from major selection bias matter more than numerical precision. For automated reporting, the API returns the same deterministic calculation and costs $0.002 per request, but the surrounding study design still determines whether the interval supports a sound conclusion.
What you can do with it
Compare conversion rates
Estimate the difference between conversion proportions for two independently assigned groups and report uncertainty alongside the point estimate.
Contrast survey response rates
Summarize how two independently sampled populations differ on the same yes-or-no survey item.
Report a risk difference
Express the absolute difference in observed event proportions between two independent cohorts with a reproducible interval.
FAQ
Which direction is the difference calculated?
The result is proportion one minus proportion two. Swap the groups if you need the opposite direction.
Should I enter 62 or 0.62 for 62 percent?
Enter 0.62. Each proportion must be a decimal from zero through one, inclusive.
Why can a bound be outside minus one or one?
The ordinary unpooled Wald formula is not range preserving. The calculator reports its unmodified limits so the selected method remains transparent.
Can I use this for paired observations?
No. The formula assumes independent samples. Matched pairs and repeated measurements require a paired-proportion method.
What happens when a sample size is below one?
The request returns an invalid-input error because a proportion cannot be associated with an empty or negative sample.
What does API use cost?
Each API request costs $0.002; the browser calculation is also available without an API request.
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/stat/ci-diff-proportions \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"proportion_1":0.62,"size_1":200,"proportion_2":0.51,"size_2":180,"confidence_level":0.95}'const res = await fetch("https://api.kit.forhosting.com/stat/ci-diff-proportions", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"proportion_1": 0.62,
"size_1": 200,
"proportion_2": 0.51,
"size_2": 180,
"confidence_level": 0.95
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/stat/ci-diff-proportions",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"proportion_1": 0.62,
"size_1": 200,
"proportion_2": 0.51,
"size_2": 180,
"confidence_level": 0.95
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/stat/ci-diff-proportions", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"proportion_1":0.62,"size_1":200,"proportion_2":0.51,"size_2":180,"confidence_level":0.95}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"proportion_1":0.62,"size_1":200,"proportion_2":0.51,"size_2":180,"confidence_level":0.95}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/stat/ci-diff-proportions", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"proportion_1": 0.62,
"size_1": 200,
"proportion_2": 0.51,
"size_2": 180,
"confidence_level": 0.95
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "stat.ci_diff_proportions",
"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. |