Skip to content
Back to Learn
·5 min read

JSON Encoding UTF-8 Guide: Unicode, Special Characters, and Best Practices

JSON text is defined to use Unicode, and the specification requires UTF-8 encoding for interchange (RFC 8259). However, encoding issues are among the most common JSON problems — from garbled characters and escape sequence errors to BOM handling and encoding detection. This guide covers JSON and UTF-8 in depth, including character encoding basics, escape sequences, surrogate pairs, and cross-language encoding behavior. Use our JSON Escape/Unescape tool to handle special characters and JSON Validator to detect encoding issues.

Understanding JSON and UTF-8

JSON text SHALL be encoded in UTF-8 (RFC 8259, Section 8.1). UTF-8 encodes each Unicode code point as 1 to 4 bytes, with ASCII characters (U+0000 to U+007F) using a single byte. This makes JSON backwards-compatible with ASCII while supporting the full Unicode range.

Character RangeCode PointsUTF-8 BytesExample
ASCIIU+0000 to U+007F1 byteA = 0x41
Latin, Greek, CyrillicU+0080 to U+07FF2 bytesé = 0xC3 0xA9
CJK, SymbolsU+0800 to U+FFFF3 bytes中 = 0xE4 0xB8 0xAD
Emoji, Rare CJKU+10000 to U+10FFFF4 bytes🚀 = 0xF0 0x9F 0x9A 0x80

JSON Escape Sequences

// Standard JSON escape sequences
{
  "tab": "	",
  "newline": "
",
  "carriageReturn": "
",
  "backslash": "\\",
  "doubleQuote": """,
  "slash": "\/",
  "backspace": "\b",
  "formfeed": "\f",
  "unicode4digit": "\u0048",
  "unicodeSurrogate": "\uD83D\uDE80"  // 🚀 as surrogate pair
}

// Usage in different languages
// JavaScript
JSON.parse('{"emoji": "\uD83D\uDE80"}');  // { emoji: '🚀' }

// Python
import json
json.loads('{"emoji": "\uD83D\uDE80"}')  // {'emoji': '🚀'}

// Go
import "encoding/json"
var data map[string]interface{}
json.Unmarshal([]byte(jsonStr), &data)

Common Encoding Problems and Solutions

ProblemSymptomCauseSolution
Mojibake (garbled text)é instead of éUTF-8 bytes interpreted as Latin-1Ensure Content-Type: application/json; charset=utf-8
BOM at start of JSONJSON.parse fails on first characterUTF-8 BOM (0xEF 0xBB 0xBF) not expectedStrip BOM before parsing
Invalid escape sequenceInvalid Unicode escapeLone surrogate or invalid hexUse JSON Escape/Unescape to fix
Emoji serializationEmoji converted to \uXXXXPython json.dumps with ensure_ascii=TrueSet ensure_ascii=False
Non-UTF-8 encodingJSON parser throws error on high bytesFile saved as ISO-8859-1 or Windows-1252Convert file to UTF-8

Handling BOM in JSON

// JavaScript: Strip BOM before parsing
function parseJSON(str) {
  // Remove UTF-8 BOM if present
  if (str.charCodeAt(0) === 0xFEFF) {
    str = str.slice(1);
  }
  return JSON.parse(str);
}

// Python: Handle BOM
import json
def load_json(filename):
    with open(filename, 'r', encoding='utf-8-sig') as f:
        return json.load(f)  # utf-8-sig handles BOM

// Go: Handle BOM
import "strings"
func parseJSON(data []byte) (interface{}, error) {
    s := string(data)
    s = strings.TrimPrefix(s, "\uFEFF")  // Remove BOM
    var result interface{}
    err := json.Unmarshal([]byte(s), &result)
    return result, err
}

Surrogate Pairs and Emoji

// Emoji characters use surrogate pairs in JSON escape
// 🚀 (U+1F680) is encoded as surrogate pair

// JavaScript handles this transparently
JSON.stringify("🚀");  // "🚀" (or "\uD83D\uDE80" depending on context)

// Python: U0001f680 or the surrogate pair
import json
json.loads('"\uD83D\uDE80"')  # '🚀'
json.dumps('🚀', ensure_ascii=True)   # '"\ud83d\ude80"'
json.dumps('🚀', ensure_ascii=False)  # '"🚀"'

Encoding in API Responses

// Server-side: Always set charset
Content-Type: application/json; charset=utf-8

// Node.js/Express
res.setHeader('Content-Type', 'application/json; charset=utf-8');

// Python/Flask
from flask import jsonify
@app.route('/api/data')
def get_data():
    return jsonify(data)  # Flask sets charset=utf-8 automatically

// Java/Spring
@GetMapping(value = "/api/data", produces = "application/json; charset=utf-8")
public Data getData() { ... }

Detecting Encoding Issues

Use our JSON Validator to detect encoding problems in your JSON. Common flags include:

  • Non-UTF-8 byte sequences (common with copy-pasted content)
  • Invalid escape sequences (lone surrogates, bad hex)
  • BOM presence (reported at position 0)
  • Overlong UTF-8 sequences (security issue)

Next Steps

Escape or unescape JSON strings with JSON Escape/Unescape. Validate encoding with JSON Validator. Format JSON output with JSON Formatter.