CRC-16 Modbus checksum
A Modbus RTU request reading ten holding registers from register 0 of device 1 gets the CRC CDC5, sent as C5 CD. Paste a frame as hex or plain text to get the 16-bit value with its bytes in wire order. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Text
- 123456789
- Crc hex
- 4B37
- Crc int
- 19,255
- Crc lo
- 37
- Crc hi
- 4B
CRC-16 Modbus is the cyclic redundancy check that rides at the end of almost every Modbus RTU frame on serial and many industrial buses. Programmers, PLC integrators, and protocol testers need a single deterministic number when they build a request, validate a response, or debug a corrupted packet on the wire. This capability accepts either plain UTF-8 text or a hex dump of bytes, runs the standard CRC-16/MODBUS algorithm with polynomial 0xA001 and initial value 0xFFFF, and returns the sixteen-bit result in uppercase hexadecimal together with the low and high bytes in Modbus transmission order.
What CRC-16 Modbus is and why industrial tools need it
A cyclic redundancy check folds every data byte through a fixed polynomial so that a single flipped bit almost always changes the residual. Modbus RTU adopted a specific sixteen-bit CRC: the generator is the reflected polynomial 0xA001 (equivalent to 0x8005 in non-reflected form), the register starts at 0xFFFF, each data byte is exclusive-ored into the low eight bits, and eight shift-and-conditional-xor steps follow per byte with no final exclusive-or.
The resulting sixteen-bit word is appended to the frame low byte first, then high byte—the order electricians and protocol analyzers expect when they read a scope or a serial sniffer. Textbooks and chip datasheets call this profile CRC-16/MODBUS; online calculators sometimes use different initials or polynomials and silently disagree with a PLC. Use it whenever you assemble or verify Modbus RTU, many meter protocols that borrowed the same CRC, or any custom binary frame that specifies CRC-16 Modbus by name.
What you can do with it
Capture analysis and debugging
Paste hex dumps from a serial sniffer in hex mode to recompute the CRC and spot truncated or corrupted industrial frames quickly.
FAQ
What polynomial and initial value does this use?
CRC-16/MODBUS: reflected polynomial 0xA001, initial register 0xFFFF, no final XOR. This matches PLC and meter implementations used on Modbus RTU.
In which order are the CRC bytes sent in a Modbus frame?
Low byte first, then high byte. A CRC of 4B37 therefore travels as 37 followed by 4B, which is the order a scope or serial sniffer shows. The tool returns both bytes separately and in wire order.
Can I paste a hex dump from a serial sniffer?
Yes. Switch to hex mode and paste the bytes: spaces, colons, hyphens, underscores, commas and 0x prefixes are removed first. What remains must be an even number of hexadecimal digits, or the tool reports malformed hex.
Why does another online calculator give a different CRC?
Some calculators use a different starting value or polynomial and silently disagree with a PLC. Check with the text 123456789: CRC-16 Modbus must give 4B37. Any other result means a different profile.
Can I checksum an empty message?
Yes. In text mode an empty string is accepted and returns FFFF, the register's starting value, because no byte has been processed. Any other text is encoded as UTF-8 before the calculation.
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/enc/crc16-modbus \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"123456789"}'const res = await fetch("https://api.kit.forhosting.com/enc/crc16-modbus", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "123456789"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/enc/crc16-modbus",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "123456789"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/enc/crc16-modbus", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"123456789"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"123456789"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/enc/crc16-modbus", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "123456789"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "enc.crc16_modbus",
"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
Malformed hex—odd digit counts or non-hex characters—fails with invalid_input instead of inventing a checksum.
What CRC-16 Modbus is and why industrial tools need it
This endpoint hard-codes the industrial profile so that the string one-two-three-four-five-six-seven-eight-nine yields the well-known residual 0x4B37, and a classic read-holding-registers request such as address one, function three, starting register zero, quantity ten yields 0xCDC5 with wire order C5 CD.
Input contract, hex parsing, and response fields
In hex mode the string is interpreted as a byte sequence: optional 0x prefixes, spaces, colons, hyphens, underscores, and commas are stripped first, then remaining characters must form an even-length run of hexadecimal digits only. Failed validation is not billed. POST a JSON body with required string field text and optional input_format of text or hex, defaulting to text. In text mode the string is encoded as UTF-8 and every resulting byte enters the CRC; empty text is allowed and yields residual FFFF for a zero-length payload. An odd number of digits after stripping, or any character outside zero through nine and A through F, raises invalid_input with a message that names malformed hex so clients can surface the error next to the field without guessing. On success the body includes crc_hex as four uppercase hex digits, crc_int as the unsigned integer zero through sixty-five thousand five hundred thirty-five, crc_lo and crc_hi as the low and high bytes of that word, wire_hex as the two-byte little-endian transmission order used on Modbus RTU, byte_count of the interpreted payload, the echoed input_format, and fixed algorithm, poly, and init strings documenting CRC-16/MODBUS with 0xA001 and 0xFFFF. Alias keys data, payload, value, and input are accepted for the payload; format, mode, and encoding alias input_format. Keep payloads modest for browser use; the algorithm itself is linear in byte length and entirely in-memory.
Where a CRC-16 Modbus API earns its keep
Protocol reverse engineers and security researchers recompute residuals over captured traffic to separate clean frames from noise without standing up a full stack. Content sites that rank for CRC-16 Modbus checksum gain a live calculator whose free path matches the automation path byte-for-byte. Keep requests deterministic, pin the known vector one-two-three-four-five-six-seven-eight-nine equals four B three seven in regression suites, and you get industrial-grade reproducibility without embedding CRC tables in every microservice.
Integration use cases
Modbus RTU frame assembly
Build address, function, and data bytes, then append the returned wire_hex trailer so the CRC low byte is transmitted first as Modbus RTU requires.
Firmware and CI golden checks
Assert that device code and server-side tooling both produce crc_hex 4B37 for ASCII 123456789 and the documented residual for your fixed request templates.
Technical questions
How do I compute a CRC-16 Modbus checksum?
Send text as UTF-8 with input_format text (default), or a hex byte string with input_format hex. The API returns crc_hex, crc_int, low/high bytes, and wire_hex in Modbus RTU order.
What happens if my hex string is malformed?
Odd digit counts after stripping separators, or any non-hex character, fail with invalid_input and a message that reports malformed hex. Those failures are not billed.
What is wire_hex versus crc_hex?
crc_hex is the sixteen-bit residual as four hex digits (high nibble of the high byte first in the string). wire_hex is low byte then high byte—the order appended on the Modbus RTU wire.
What does the CRC-16 Modbus checksum tool cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.