Skip to content

fix(seo): wrap home page JSON-LD in @graph to add top-level @context#20

Merged
leoisadev1 merged 1 commit into
mainfrom
posthog-code/seo-jsonld-graph-context
Jun 13, 2026
Merged

fix(seo): wrap home page JSON-LD in @graph to add top-level @context#20
leoisadev1 merged 1 commit into
mainfrom
posthog-code/seo-jsonld-graph-context

Conversation

@posthog

@posthog posthog Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Visitors hit an unhandled TypeError: undefined is not an object (evaluating 'r["@context"].toLowerCase') on the amend.sh home page (captured by error tracking on 2026-06-06, Safari 26.3 / macOS).

Root cause: apps/web/src/routes/index.tsx injected the page's JSON-LD as a bare top-level array:

JSON.stringify([organizationJsonLd, productJsonLd, faqJsonLd])

Each object carried its own @context, but the array itself had none. Any consumer that treats the parsed JSON-LD as a single object reads r["@context"]undefined and crashes calling .toLowerCase() on it. The crashing code is third-party/injected (a browser extension or structured-data reader), so it can't be edited directly — but the array shape is what triggers it.

Fix

Give the JSON-LD a single top-level @context by wrapping the three entities in a @graph, and drop the now-redundant per-object @context in seo.ts:

JSON.stringify({
  "@context": "https://schema.org",
  "@graph": [organizationJsonLd, productJsonLd, faqJsonLd],
})

This fixes the crash trigger and produces a more standard structured-data shape.

Notes

  • organizationJsonLd, productJsonLd, and faqJsonLd are only consumed in index.tsx, so removing their per-object @context is safe.
  • Could not run check-types in this environment (pnpm catalog/install error unrelated to this change), but the edits are mechanical and valid TypeScript.

Resolves PostHog inbox report 019ec185-73e0-7f4a-a0cf-26b2dfa5d321.

🤖 Generated with Claude Code

The home page injected its JSON-LD as a bare top-level array
(`[organizationJsonLd, productJsonLd, faqJsonLd]`). Each object carried
its own `@context`, but the array itself had none, so consumers that
treat the parsed JSON-LD as a single object read `r["@context"]` →
`undefined` and crashed calling `.toLowerCase()` on it. Error tracking
captured an unhandled `TypeError: undefined is not an object (evaluating
'r["@context"].toLowerCase')` from an injected structured-data reader on
amend.sh.

Wrap the three entities in a single `@graph` with one top-level
`@context` and drop the now-redundant per-object `@context`. This fixes
the crash trigger and produces a more standard structured-data shape.

Resolves PostHog inbox report 019ec185-73e0-7f4a-a0cf-26b2dfa5d321.

Generated-By: PostHog Code
Task-Id: 38c8d80f-f631-448e-a9d6-88d20c7dd846
@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a crash on the home page caused by a browser extension or structured-data reader calling .toLowerCase() on r["@context"], which was undefined because the JSON-LD was emitted as a bare array with no top-level context. The fix wraps the three schema.org entities in a standard @graph document with a single top-level @context, and removes the now-redundant per-object @context fields.

  • apps/web/src/routes/index.tsx: JSON-LD output changed from JSON.stringify([...]) to JSON.stringify({ \"@context\": \"...\", \"@graph\": [...] }) — the correct fix for the crash and also the recommended JSON-LD shape for multiple entities.
  • apps/web/src/lib/seo.ts: @context removed from faqJsonLd, productJsonLd, and organizationJsonLd. Currently safe since all three are only consumed in index.tsx, but the exported objects are now incomplete if used standalone.

Confidence Score: 4/5

The fix is correct and directly addresses the crash. The only concern is that the three exported JSON-LD objects no longer carry their own @context, making them silently invalid if imported in a new route without @graph wrapping.

The core change — wrapping the entities in a @graph document — is the right approach and matches the JSON-LD spec. The export-level removal of @context from each object is technically sound today but leaves a maintenance trap: any new page that imports one of these objects and injects it directly will produce malformed structured data with no compile-time warning.

apps/web/src/lib/seo.ts — the exported JSON-LD objects now lack @context and rely on callers always wrapping them in @graph

Important Files Changed

Filename Overview
apps/web/src/lib/seo.ts Removed @context from all three JSON-LD objects; safe today (only used in index.tsx via @graph) but the exported objects are now incomplete standalone and could cause silent JSON-LD failures if imported elsewhere in future.
apps/web/src/routes/index.tsx Replaces bare array with a proper @graph document with top-level @context — correct JSON-LD structure, directly fixes the crash trigger.

Sequence Diagram

sequenceDiagram
    participant index.tsx
    participant seo.ts
    participant Browser
    participant Reader as StructuredDataReader

    index.tsx->>seo.ts: import organizationJsonLd, productJsonLd, faqJsonLd
    index.tsx->>Browser: render script tag with JSON-LD

    note over Browser,Reader: Before fix - bare array, no top-level @context
    Browser->>Reader: parse JSON array
    Reader-->>Browser: "TypeError on r["@context"].toLowerCase()"

    note over Browser,Reader: After fix - @graph document with @context
    Browser->>Reader: "parse @graph document"
    Reader->>Reader: "r["@context"] = "https://schema.org""
    Reader-->>Browser: structured data processed OK
Loading

Comments Outside Diff (1)

  1. apps/web/src/lib/seo.ts, line 154-160 (link)

    P2 Exported objects silently invalid if used standalone — The three JSON-LD objects (organizationJsonLd, productJsonLd, faqJsonLd) are now exported without @context, so any future route that imports one of them and injects it directly (without wrapping in @graph) would produce invalid JSON-LD that is silently ignored by search crawlers. There's no type-level guard preventing this. They are only consumed in index.tsx today, so this is safe right now, but the risk grows as the app adds more pages. Score: 2/5 — low likelihood currently, but the exported API now has a hidden constraint. Consider either keeping @context on each object (redundant inside @graph but harmless) or keeping them as unexported internal constants if they're truly only ever used together in one @graph.

    Fix in Codex

Fix All in Codex

Reviews (1): Last reviewed commit: "fix(seo): wrap home page JSON-LD in @gra..." | Re-trigger Greptile

@leoisadev1 leoisadev1 merged commit 81cdaf8 into main Jun 13, 2026
3 of 4 checks passed
@leoisadev1 leoisadev1 deleted the posthog-code/seo-jsonld-graph-context branch June 13, 2026 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant