BlueSky facets and byte offset calculator
Calculate byteStart and byteEnd ranges for app.bsky.richtext.facet links, mentions, and tags when emoji, accents, or non-English text make normal string positions unreliable.
Calculate a facet span
BlueSky facets use zero-indexed UTF-8 byte offsets with an inclusive start and exclusive end. JavaScript string indexes are UTF-16, so this tool converts the range before building JSON.
UTF-8 byte map
| Text | Code point | UTF-16 range | Byte range | Bytes |
|---|---|---|---|---|
| C | U+0043 | 0-1 | 0-1 | 1 |
| a | U+0061 | 1-2 | 1-2 | 1 |
| f | U+0066 | 2-3 | 2-3 | 1 |
| e | U+0065 | 3-4 | 3-4 | 1 |
| space | U+0020 | 4-5 | 4-5 | 1 |
| n | U+006E | 5-6 | 5-6 | 1 |
| o | U+006F | 6-7 | 6-7 | 1 |
| t | U+0074 | 7-8 | 7-8 | 1 |
| e | U+0065 | 8-9 | 8-9 | 1 |
| s | U+0073 | 9-10 | 9-10 | 1 |
| space | U+0020 | 10-11 | 10-11 | 1 |
| f | U+0066 | 11-12 | 11-12 | 1 |
| o | U+006F | 12-13 | 12-13 | 1 |
| r | U+0072 | 13-14 | 13-14 | 1 |
| space | U+0020 | 14-15 | 14-15 | 1 |
| @ | U+0040 | 15-16 | 15-16 | 1 |
| o | U+006F | 16-17 | 16-17 | 1 |
| n | U+006E | 17-18 | 17-18 | 1 |
| y | U+0079 | 18-19 | 18-19 | 1 |
| x | U+0078 | 19-20 | 19-20 | 1 |
| h | U+0068 | 20-21 | 20-21 | 1 |
| q | U+0071 | 21-22 | 21-22 | 1 |
| . | U+002E | 22-23 | 22-23 | 1 |
| u | U+0075 | 23-24 | 23-24 | 1 |
| s | U+0073 | 24-25 | 24-25 | 1 |
| : | U+003A | 25-26 | 25-26 | 1 |
| space | U+0020 | 26-27 | 26-27 | 1 |
| c | U+0063 | 27-28 | 27-28 | 1 |
| a | U+0061 | 28-29 | 28-29 | 1 |
| l | U+006C | 29-30 | 29-30 | 1 |
| c | U+0063 | 30-31 | 30-31 | 1 |
| u | U+0075 | 31-32 | 31-32 | 1 |
| l | U+006C | 32-33 | 32-33 | 1 |
| a | U+0061 | 33-34 | 33-34 | 1 |
| t | U+0074 | 34-35 | 34-35 | 1 |
| e | U+0065 | 35-36 | 35-36 | 1 |
| space | U+0020 | 36-37 | 36-37 | 1 |
| f | U+0066 | 37-38 | 37-38 | 1 |
| a | U+0061 | 38-39 | 38-39 | 1 |
| c | U+0063 | 39-40 | 39-40 | 1 |
| e | U+0065 | 40-41 | 40-41 | 1 |
| t | U+0074 | 41-42 | 41-42 | 1 |
| s | U+0073 | 42-43 | 42-43 | 1 |
| space | U+0020 | 43-44 | 43-44 | 1 |
| b | U+0062 | 44-45 | 44-45 | 1 |
| e | U+0065 | 45-46 | 45-46 | 1 |
| f | U+0066 | 46-47 | 46-47 | 1 |
| o | U+006F | 47-48 | 47-48 | 1 |
| r | U+0072 | 48-49 | 48-49 | 1 |
| e | U+0065 | 49-50 | 49-50 | 1 |
| space | U+0020 | 50-51 | 50-51 | 1 |
| p | U+0070 | 51-52 | 51-52 | 1 |
| o | U+006F | 52-53 | 52-53 | 1 |
| s | U+0073 | 53-54 | 53-54 | 1 |
| t | U+0074 | 54-55 | 54-55 | 1 |
| i | U+0069 | 55-56 | 55-56 | 1 |
| n | U+006E | 56-57 | 56-57 | 1 |
| g | U+0067 | 57-58 | 57-58 | 1 |
| space | U+0020 | 58-59 | 58-59 | 1 |
| h | U+0068 | 59-60 | 59-60 | 1 |
| t | U+0074 | 60-61 | 60-61 | 1 |
| t | U+0074 | 61-62 | 61-62 | 1 |
| p | U+0070 | 62-63 | 62-63 | 1 |
| s | U+0073 | 63-64 | 63-64 | 1 |
| : | U+003A | 64-65 | 64-65 | 1 |
| / | U+002F | 65-66 | 65-66 | 1 |
| / | U+002F | 66-67 | 66-67 | 1 |
| o | U+006F | 67-68 | 67-68 | 1 |
| n | U+006E | 68-69 | 68-69 | 1 |
| y | U+0079 | 69-70 | 69-70 | 1 |
| x | U+0078 | 70-71 | 70-71 | 1 |
| h | U+0068 | 71-72 | 71-72 | 1 |
| q | U+0071 | 72-73 | 72-73 | 1 |
| . | U+002E | 73-74 | 73-74 | 1 |
| u | U+0075 | 74-75 | 74-75 | 1 |
| s | U+0073 | 75-76 | 75-76 | 1 |
| / | U+002F | 76-77 | 76-77 | 1 |
| t | U+0074 | 77-78 | 77-78 | 1 |
| o | U+006F | 78-79 | 78-79 | 1 |
| o | U+006F | 79-80 | 79-80 | 1 |
| l | U+006C | 80-81 | 80-81 | 1 |
| s | U+0073 | 81-82 | 81-82 | 1 |
| space | U+0020 | 82-83 | 82-83 | 1 |
| # | U+0023 | 83-84 | 83-84 | 1 |
| B | U+0042 | 84-85 | 84-85 | 1 |
| l | U+006C | 85-86 | 85-86 | 1 |
| u | U+0075 | 86-87 | 86-87 | 1 |
| e | U+0065 | 87-88 | 87-88 | 1 |
| S | U+0053 | 88-89 | 88-89 | 1 |
| k | U+006B | 89-90 | 89-90 | 1 |
| y | U+0079 | 90-91 | 90-91 | 1 |
Inclusive start, exclusive end
A facet starts at byteStart and stops before byteEnd. The selected byte length is byteEnd minus byteStart.
Mentions need DIDs
The visible text may be a handle, but the mention facet stores a DID. Resolve handles before writing a final post record.
Official references
Keep byte math out of normal publishing
Byte offsets matter for custom AT Protocol tooling. For day-to-day growth, ONYX helps you write, review, schedule, and publish BlueSky posts from a content calendar without manually assembling rich text facet JSON.
Start Free