An identifier is a claim about identity

When you paste a JSON-LD document into a viewer, the thing you are looking at is not a tree of nested objects. It is a labeled directed graph: nodes connected by directed arcs. The JSON-LD 1.1 Recommendation describes a graph as a set of nodes connected by directed arcs, and says every arc is labeled with an IRI or a blank node identifier — called a property in JSON-LD syntax. Identifiers are what let you say "this arc arriving here and this arc leaving there touch the same node."

That is the whole job. An @id is not decoration and not a URL you are expected to visit. It is the statement that two mentions of a string refer to the same node inside this document.

Because of that, an identifier-driven view of a document behaves differently from a nested-object view. The nested view shows you where things sit. The identifier view shows you what they touch, including touching across the tree.

Three kinds of identifier (and a fourth you may not notice)

IRIs and compact IRIs

A node object's @id value must be an IRI reference or a compact IRI, and the specification explicitly includes blank node identifiers in that allowance. Compact IRIs and terms resolve through the active context, so the string you typed and the identifier the graph actually uses can differ.

The specification also states that IRIs used within a graph should return a Linked Data document when dereferenced. That is guidance about publication practice, not a condition a checker can test offline. A visualizer that runs locally and fetches nothing cannot know whether https://example.org/thing/7 resolves to anything at all — and a viewer should not pretend otherwise.

Blank node identifiers

Blank nodes are identified by strings beginning with _:, and those identifiers are scoped to the document. This scoping matters more than it first appears. Two separately pasted documents that both use _:b0 are not talking about the same node. A comparison view should therefore treat blank node labels as local to each version rather than as stable keys that survive a version bump. If you diff two documents and _:b0 changed meaning between them, a naive label match will invent continuity that isn't there.

Graph names

A JSON-LD document serializes a dataset: exactly one default graph plus zero or more named graphs. The default graph has no name and may be empty. Each named graph pairs a name — an IRI or blank node identifier — with a graph. A node object that carries both @graph and @id uses that @id as the named graph's name.

There is a fourth, invisible case. A simple graph object has @graph but no @id; in the data model it still receives a graph name as an implicitly allocated blank node identifier. Your inspector should label these as implicit, because you did not write that name and cannot cite it.

Property identifiers

Arc labels are identifiers too. The specification allows blank node identifiers as property labels but notes this is obsolete and may be removed, pointing toward a document-relative IRI such as #. When you see a property you cannot expand, the likely answer is not "invalid" but "not mapped through context," which leads to the next point.

When the same identifier appears twice

This is the case most likely to be misread as an error, and it is often the opposite. The specification says a node's properties may be spread among different node objects in a document, and when that happens the keys of the different node objects are merged to create the properties of the resulting node.

So a graph can legitimately define a partial view of a node in one place and complete it elsewhere. A viewer that flags every repeated @id as a duplicate error is reporting its own difficulty, not the document's. The honest diagnostic is a merge: show that the node has contributions from multiple locations, note which keys came from where if key collisions exist, and reserve stronger language for actual conflicts such as the same key given two different values in the same node.

Worked hypothetical: a merged node across two graphs

Consider a hypothetical document with two named graphs plus default-graph contribution. One graph contains an organization node identified as https://example.org/org/demo with a name. A second graph contains a node with the same @id and a founder arc. The default graph carries a third object with that identifier and a description.

Structurally, this is one node with three incoming contributions — not three organizations. A useful inspector selects the identifier once, shows all incident arcs together, marks each arc's source graph, and lists statement counts per graph. Nothing here is a misconfiguration; it is the intended mechanism. The example is illustrative, not drawn from any published dataset.

External identifiers are references, not fetches

Nothing in the grammar requires an identifier to be dereferenceable, and nothing restricts @id to domains you control. schema.org's data model page makes the same point from the other direction: because JSON-LD reserves a built-in representation for URIs via @id, the identifier property and its sub-properties are mainly useful where content is expressed as a textual string or where alternative identifiers such as DOIs are needed. The general preference runs toward @id; it does not make a textual identifier wrong.

Practically, this means a local tool should accept an identifier pointing at any host and simply mark it as external and unresolved. It should never attempt to contact it. That is both a correctness position and the reason such a tool can run entirely in the browser without sending your document anywhere.

What identifier checks can and cannot decide

A structural check can tell you whether @id values are syntactically well-formed references, whether a repeated identifier merges cleanly or collides, whether a graph object lacks an explicit name, and whether a node participates in the graph at all.

That last one has a real rule behind it. The data model states a graph must not contain unconnected nodes, which effectively prohibits unnested empty node objects and unnested node objects containing only @id. Unrelated nodes are fine as long as properties are defined or they are referenced elsewhere. Reporting an unconnected node is a legitimate structural finding — but it is about connectivity, not about whether your page will receive any particular search treatment.

And that limit is the one worth stating plainly. schema.org describes its type and property associations as closer to guidelines than formal rules, says checkers may warn about ambiguous data but are not obliged to treat unexpected structures as errors, and expects entities to combine independent types. Its open-world stance means an absent property is unknown, not false. So an inspector can show you the shape of your graph accurately and still tell you nothing about eligibility for any downstream feature. These pages make no validation claim and no eligibility claim, and neither should any tool you build on the same reading.

A practical next step

Take one document you maintain. Find every distinct @id in it and count how many node objects reference each one. Then ask, for each identifier, whether the merge is intentional: did you mean to complete that node from a second location, or did two authors independently invent the same identifier for different things? That question — intent, not syntax — is where real defects hide, and it is the reason identifiers deserve their own inspector panel rather than a footnote.