Labels per sheet calculator
The labels per sheet calculator finds the row count, column count, and total capacity of a rectangular grid before you print or order stock.
Run — free
Enter the sheet and label dimensions in one consistent unit, then reserve any top, right, bottom, and left margins required by the printer. Optional horizontal and vertical gaps account for spacing between labels. The result also reports usable, occupied, and unused dimensions, making it easier to verify that a proposed layout fits without silently scaling the labels.
Enter every dimension in one consistent unit
Start with the physical width and height of the sheet and of a single finished label. You can use millimetres, inches, points, or another measurement unit, because the calculation uses ratios and preserves the values rather than converting them. The important rule is that every supplied dimension must use the same unit. A sheet entered in millimetres cannot be combined with a label entered in inches. Use the label's actual cut size, not the artwork size after a print driver has scaled it. All sheet and label dimensions must be finite values greater than zero. This catches missing measurements, negative dimensions, and accidental text values before they produce a misleading count. Orientation also matters: sheet_width and label_width describe the horizontal direction, while the height fields describe the vertical direction. If labels may be rotated, run a second calculation with label width and height exchanged, then compare the totals. The calculator does not rotate labels automatically because artwork, grain direction, applicator requirements, or readable text may make one orientation mandatory.
Reserve margins and gaps before counting cells
Margins describe the parts of the sheet that cannot hold labels. Enter top, right, bottom, and left values independently so the layout can represent printers with asymmetric non-printable areas or stock with unequal edge waste. Omitted margins default to zero. The combined left and right margins may equal the sheet width, but they cannot exceed it; the same rule applies to top and bottom margins. Horizontal_gap is the clear distance between neighboring columns, and vertical_gap is the distance between neighboring rows. Gaps occur only between labels, never outside the first or last label, so a row with three labels contains two horizontal gaps. Both gap values default to zero and cannot be negative. The usable width is the sheet width after subtracting left and right margins, and usable height is calculated in the same way. A column fits when its label width and all required preceding gaps stay within usable width. This distinction prevents the common mistake of charging a gap after the final label and undercounting a layout that fits exactly.
Interpret the capacity and leftover-space results
The result reports columns, rows, and labels_per_sheet. Columns and rows are whole numbers because a partially fitting label is not usable, and their product is the total capacity of the grid. A valid layout may return zero columns, zero rows, or zero labels when the available area is smaller than a label; this is a fit result, not malformed input. The usable dimensions show the area remaining after margins. Occupied dimensions cover the labels and internal gaps in each direction, while unused dimensions show the leftover space inside the usable area. Those leftovers are not automatically divided or centered. For a centered grid, add half of unused_width to the left margin and half of unused_height to the top margin when positioning the first label. The calculation assumes axis-aligned rectangular labels in a regular grid. It does not add bleed, crop marks, printer tolerances, rounded-corner clearance, or space for registration marks unless you explicitly include those needs in the label dimensions, margins, or gaps. Confirm the resulting geometry against the printer specification before producing a large run.
What you can do with it
Plan custom label stock
Compare label dimensions and gaps against a chosen sheet before ordering dies, stock, or a production run.
Configure a print template
Get exact grid counts and leftover space for positioning labels in a document or print-layout application.
Compare label orientations
Run the calculation in portrait and rotated orientations to identify the higher-capacity valid grid.
FAQ
What does it cost?
Each API request costs $0.002. The same deterministic calculation can also run in the browser.
Which measurement units can I use?
Any linear unit works, including millimetres and inches, provided every dimension in one request uses that same unit.
Are gaps included after the last label?
No. Gaps are counted only between adjacent labels, so n labels in a row require n minus one gaps.
What happens if a label does not fit?
The calculator returns a zero count for the direction that cannot fit a label, and labels_per_sheet is zero.
Does the calculator rotate labels for the best fit?
No. It uses the supplied orientation. Swap label_width and label_height in a second request to evaluate rotation.
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/doc/labels-per-sheet \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"sheet_width":210,"sheet_height":297,"label_width":63.5,"label_height":38.1}'const res = await fetch("https://api.kit.forhosting.com/doc/labels-per-sheet", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"sheet_width": 210,
"sheet_height": 297,
"label_width": 63.5,
"label_height": 38.1
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/doc/labels-per-sheet",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"sheet_width": 210,
"sheet_height": 297,
"label_width": 63.5,
"label_height": 38.1
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/doc/labels-per-sheet", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"sheet_width":210,"sheet_height":297,"label_width":63.5,"label_height":38.1}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"sheet_width":210,"sheet_height":297,"label_width":63.5,"label_height":38.1}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/doc/labels-per-sheet", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"sheet_width": 210,
"sheet_height": 297,
"label_width": 63.5,
"label_height": 38.1
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "doc.labels_per_sheet",
"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_mb | 25 |
max_pages | 200 |
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. |