diff --git a/graphify/exporters/html.py b/graphify/exporters/html.py
index 14f781249..1fbe8eb10 100644
--- a/graphify/exporters/html.py
+++ b/graphify/exporters/html.py
@@ -613,9 +613,13 @@ def to_html(
n = member_counts.get(cid, len(communities.get(cid, []))) if member_counts else len(communities.get(cid, []))
legend_data.append({"cid": cid, "color": color, "label": lbl, "count": n})
- # Escape sequences so embedded JSON cannot break out of the script tag
+ # Escape every `<` as < so embedded JSON cannot break out of the ` no longer closes the tag and the page goes
+ # blank (#4124). `<` round-trips through JSON.parse, so labels render unchanged.
def _js_safe(obj) -> str:
- return json.dumps(obj).replace("", "<\\/")
+ return json.dumps(obj).replace("<", "\\u003c")
nodes_json = _js_safe(vis_nodes)
edges_json = _js_safe(vis_edges)
diff --git a/graphify/tree_html.py b/graphify/tree_html.py
index dfb41343a..77630868d 100644
--- a/graphify/tree_html.py
+++ b/graphify/tree_html.py
@@ -568,9 +568,10 @@ def emit_html(
svg_width: int = 6000,
svg_height: int = 8000,
) -> str:
- # Escape sequences so embedded JSON cannot break out of the
- # ` no longer closes the tag — the rest of the page is swallowed
+and graph.html renders blank. Escaping every `<` as \\u003c closes all three
+breakout sequences (`