Attest tools · Text Stats: words, characters, tokens and SMS segments

Character count online

Count user-perceived characters and UTF-8 bytes in a short caption with emoji, then check a 40-character limit.

1 credit per successful call

Input JSON

{
  "text": "Fresh linen, soft cotton, simple care. 🌿",
  "limits": [
    {
      "name": "Caption",
      "unit": "characters",
      "max": 40
    }
  ]
}

Captured output JSON

{
  "characters": 40,
  "code_points": 40,
  "utf16_units": 41,
  "bytes_utf8": 43,
  "words": 6,
  "sentences": 2,
  "paragraphs": 1,
  "lines": 1,
  "whitespace": 6,
  "reading_time_minutes": 0.03,
  "speaking_time_minutes": 0.03,
  "time_basis": {
    "reading_words_per_minute": 238,
    "speaking_words_per_minute": 183
  },
  "tokens": {
    "o200k_base": 11,
    "cl100k_base": 12,
    "note": "OpenAI tokenizers, per the model table in js-tiktoken 1.0.21: o200k_base is listed for GPT-4o, GPT-4o mini, GPT-4.1, GPT-4.5 Preview, o1, o3, o4-mini and GPT-5; cl100k_base for GPT-4, GPT-4 Turbo and GPT-3.5 Turbo. Other models, including other vendors', may tokenize differently, so treat these counts as estimates for them."
  },
  "sms": {
    "encoding": "UCS-2",
    "segments": 1,
    "characters_per_segment": 70,
    "units": 41,
    "max_segments": 255,
    "within_concatenation_limit": true,
    "note": "GSM 7-bit default alphabet without national language shift tables; extension characters (^ { } [ ] ~ | \\ € and form feed) cost two. Code 0x09 is capital Ç in the 3GPP table, so small ç is counted as UCS-2, the encoding a gateway following that table sends; a gateway following Unicode's GSM0338.TXT accepts ç as one septet and may need fewer segments than reported. Multipart sizes assume (truncated)"
  },
  "limits": [
    {
      "name": "Caption",
      "unit": "characters",
      "max": 40,
      "value": 40,
      "within": true
    }
  ],
  "sources": [
    {
      "name": "Brysbaert, M. (2019). How many words do we read per minute? A review and meta-analysis of reading rate. Journal of Memory and Language, 109, 104047.",
      "url": "https://doi.org/10.1016/j.jml.2019.104047",
      "used_for": "reading_time_minutes (238 wpm, adult silent reading of non-fiction) and speaking_time_minutes (183 wpm, adult reading aloud)"
    },
    {
      "name": "OpenAI tiktoken encodings o200k_base and cl100k_base (MIT), rank files from js-tiktoken (MIT)",
      "url": "https://github.com/openai/tiktoken",
      "used_for": "tokens"
    },
    {
      "name": "3GPP TS 23.038 (GSM 7-bit default alphabet and extension table) and 3GPP TS 23.040 clause 9.2.3.24.1 (concatenated short messages)",
      "url": "https://www.3gpp.org/ftp/Specs/archive/23_series/",
      "used_for": "sms"
    },
    {
      "name": "Unicode GSM0338.TXT mapping — cited only for the divergence at GSM code 0x09, which it maps to small c-cedilla where the 3GPP table draws the capital; we follow 3GPP",
      "url": "https://www.unicode.org/Public/MAPPINGS/ETSI/GSM0338.TXT",
      "used_for": "sms"
    }
  ],
  "notice": "General information only. Reading and speaking times are averages for adult English readers; individual rates vary.",
  "checked_at": "2026-10-20T20:47:48.400Z"
}

API call

curl -s -X POST https://getattest.com.au/api/v1/text/stats \
  -H "authorization: Bearer $ATTEST_API_KEY" \
  -H "content-type: application/json" \
  --data-raw '{"text":"Fresh linen, soft cotton, simple care. 🌿","limits":[{"name":"Caption","unit":"characters","max":40}]}'

Run this call with your own bearer key. Issue an API key.

About this example

The input was validated and run locally through the registered service. The output above is a display preview of the captured service result. File bytes are described instead of printed, and strings longer than 400 characters are truncated; the HTTP API also adds call_id, credits_charged and credits_remaining. Timestamps and generated identifiers will vary.

Source: apps/api/svc/text_stats.mjs

Tool reference and limits · API key guide