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 Range | Code Points | UTF-8 Bytes | Example |
|---|---|---|---|
| ASCII | U+0000 to U+007F | 1 byte | A = 0x41 |
| Latin, Greek, Cyrillic | U+0080 to U+07FF | 2 bytes | é = 0xC3 0xA9 |
| CJK, Symbols | U+0800 to U+FFFF | 3 bytes | 丠= 0xE4 0xB8 0xAD |
| Emoji, Rare CJK | U+10000 to U+10FFFF | 4 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
| Problem | Symptom | Cause | Solution |
|---|---|---|---|
| Mojibake (garbled text) | ÃÂé instead of é | UTF-8 bytes interpreted as Latin-1 | Ensure Content-Type: application/json; charset=utf-8 |
| BOM at start of JSON | JSON.parse fails on first character | UTF-8 BOM (0xEF 0xBB 0xBF) not expected | Strip BOM before parsing |
| Invalid escape sequence | Invalid Unicode escape | Lone surrogate or invalid hex | Use JSON Escape/Unescape to fix |
| Emoji serialization | Emoji converted to \uXXXX | Python json.dumps with ensure_ascii=True | Set ensure_ascii=False |
| Non-UTF-8 encoding | JSON parser throws error on high bytes | File saved as ISO-8859-1 or Windows-1252 | Convert 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.