Skip to main content

Link Types

Links in ActivityStreams represent references to other resources. Unlike Objects, Links don't have an id property—they point to resources via href.

The base Link type for referencing external resources.

{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Link",
"href": "https://example.com/resource",
"mediaType": "text/html",
"name": "Example Resource"
}
PropertyTypeDescription
hrefURITarget resource URL (required)
relString/ArrayLink relation type
mediaTypeStringMIME type of target
nameStringHuman-readable name
hreflangStringLanguage of target resource
heightIntegerHeight in pixels (for media)
widthIntegerWidth in pixels (for media)
previewObject/LinkPreview of the resource

Links and objects can often be used interchangeably:

// As Object reference (just the URL)
{
"actor": "https://example.com/users/alice"
}

// As Link object (with metadata)
{
"actor": {
"type": "Link",
"href": "https://example.com/users/alice",
"name": "Alice"
}
}

// As embedded Object
{
"actor": {
"type": "Person",
"id": "https://example.com/users/alice",
"name": "Alice"
}
}

Mention

References an actor in content. Used for @mentions.

{
"type": "Mention",
"href": "https://example.com/users/bob",
"name": "@bob@example.com"
}

Mention in Notes

{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Note",
"content": "<p>Hello <a href=\"https://example.com/users/bob\">@bob</a>!</p>",
"tag": [
{
"type": "Mention",
"href": "https://example.com/users/bob",
"name": "@bob@example.com"
}
]
}

Mention Properties

PropertyTypeDescription
hrefURIActor's ID URL
nameString@handle format

Processing Mentions

function extractMentions(text) {
const mentionRegex = /@(\w+)@([\w.-]+)/g;
const mentions = [];
let match;

while ((match = mentionRegex.exec(text)) !== null) {
const [fullMatch, username, domain] = match;
mentions.push({
type: 'Mention',
name: fullMatch,
href: null // Will be resolved via WebFinger
});
}

return mentions;
}

async function resolveMention(mention) {
const [, username, domain] = mention.name.match(/@(\w+)@([\w.-]+)/);
const webfinger = await lookupWebFinger(`${username}@${domain}`);
mention.href = webfinger.actorUrl;
return mention;
}

For video with multiple resolutions:

{
"type": "Video",
"url": [
{
"type": "Link",
"href": "https://example.com/video-1080p.mp4",
"mediaType": "video/mp4",
"height": 1080,
"width": 1920
},
{
"type": "Link",
"href": "https://example.com/video-720p.mp4",
"mediaType": "video/mp4",
"height": 720,
"width": 1280
}
]
}

Alternate Representations

{
"type": "Article",
"id": "https://example.com/articles/1",
"url": [
{
"type": "Link",
"href": "https://example.com/articles/1",
"mediaType": "text/html",
"name": "Web version"
},
{
"type": "Link",
"href": "https://example.com/articles/1.pdf",
"mediaType": "application/pdf",
"name": "PDF version"
}
]
}

Language Variants

{
"type": "Article",
"url": [
{
"type": "Link",
"href": "https://example.com/article/en",
"hreflang": "en",
"name": "English"
},
{
"type": "Link",
"href": "https://example.com/article/de",
"hreflang": "de",
"name": "Deutsch"
}
]
}

Tag Array Usage

The tag property can contain various link types:

{
"type": "Note",
"content": "<p>Hello @bob! Check out #activitypub :blobcat:</p>",
"tag": [
{
"type": "Mention",
"href": "https://example.com/users/bob",
"name": "@bob@example.com"
},
{
"type": "Hashtag",
"href": "https://example.com/tags/activitypub",
"name": "#activitypub"
},
{
"type": "Emoji",
"id": "https://example.com/emoji/blobcat",
"name": ":blobcat:",
"icon": {
"type": "Image",
"url": "https://example.com/emoji/blobcat.png"
}
}
]
}

Hashtag

References a topic tag.

{
"type": "Hashtag",
"href": "https://example.com/tags/fediverse",
"name": "#fediverse"
}

Hashtag Properties

PropertyTypeDescription
hrefURITag page URL
nameStringTag with # prefix

Processing Hashtags

function extractHashtags(text) {
const hashtagRegex = /#(\w+)/g;
const tags = [];
let match;

while ((match = hashtagRegex.exec(text)) !== null) {
const [fullMatch, tagName] = match;
tags.push({
type: 'Hashtag',
href: `https://${config.domain}/tags/${tagName.toLowerCase()}`,
name: `#${tagName}`
});
}

return tags;
}

The rel property specifies the relationship:

{
"type": "Link",
"href": "https://example.com/profile",
"rel": "http://webfinger.net/rel/profile-page"
}

Common Relations

RelationDescription
selfCanonical representation
alternateAlternative representation
previewPreview of the resource
http://webfinger.net/rel/profile-pageProfile page
http://ostatus.org/schema/1.0/subscribeRemote follow URL

Provide previews for linked content:

{
"type": "Link",
"href": "https://example.com/video.mp4",
"mediaType": "video/mp4",
"preview": {
"type": "Image",
"url": "https://example.com/video-thumbnail.jpg"
}
}
TypePurposeKey Properties
LinkGeneric referencehref, mediaType
Mention@mentionhref, name
HashtagTopic taghref, name

Best Practices

Always Include mediaType

// Good
{
"type": "Link",
"href": "https://example.com/image.png",
"mediaType": "image/png"
}

// Less helpful
{
"type": "Link",
"href": "https://example.com/image.png"
}

Use Descriptive Names

{
"type": "Link",
"href": "https://example.com/doc.pdf",
"mediaType": "application/pdf",
"name": "User Manual (PDF, 2.3 MB)"
}

Validate href URLs

function isValidLink(link) {
if (!link.href) return false;

try {
const url = new URL(link.href);
return ['http:', 'https:'].includes(url.protocol);
} catch {
return false;
}
}

Next Steps