--- title: "ssr:render Hook" description: "Learn about the ssr:render hook in Unhead that processes tags during server-side rendering" navigation: title: "ssr:render" --- The `ssr:render` hook is called during the server-side rendering process after tags have been resolved but before they're converted to HTML strings. This hook provides access to the finalized tags and allows for last-minute modifications specific to server-side rendering. ## Hook Signature ```ts export interface Hook { 'ssr:render': (ctx: { tags: HeadTag[] }) => HookResult } ``` ### Parameters | Name | Type | Description | |------|------|-------------| | `ctx` | Object | Context object with rendering information | | `ctx.tags` | `HeadTag[]` | Array of finalized head tags being rendered | ### Returns `HookResult` which is either `void` or `Promise<void>` ## Usage Example ```ts import { createHead } from '@unhead/dynamic-import' const head = createHead({ hooks: { 'ssr:render': (ctx) => { // Log the tags being rendered in SSR console.log(`Rendering ${ctx.tags.length} tags during SSR`) // Add a server-specific meta tag ctx.tags.push({ tag: 'meta', props: { name: 'ssr-timestamp', content: Date.now().toString() } }) } } }) ``` ## Use Cases ### Server-specific Tag Modifications Modify tags specifically for server-side rendering: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' export const ssrTagsPlugin = defineHeadPlugin({ hooks: { 'ssr:render': (ctx) => { // Add SSR-specific attributes to all tags ctx.tags.forEach((tag) => { if (tag.props) { // Add data attribute to indicate this was rendered on the server tag.props['data-ssr'] = 'true' } }) // Add server-rendered timestamp ctx.tags.push({ tag: 'meta', props: { name: 'server-render-time', content: new Date().toISOString() } }) // Add cache-control meta tag for browsers ctx.tags.push({ tag: 'meta', props: { 'http-equiv': 'Cache-Control', 'content': 'no-cache, no-store, must-revalidate' } }) } } }) ``` ### Platform-specific Optimizations Apply optimizations based on the server platform: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' export const platformOptimizationPlugin = defineHeadPlugin({ hooks: { 'ssr:render': (ctx) => { // Add preload hints based on platform capabilities const isNodeJS = typeof process !== 'undefined' && process.versions && process.versions.node if (isNodeJS) { // Modern Node.js - add HTTP/2 Server Push hints through special meta tags const criticalResources = [ { path: '/css/main.css', as: 'style' }, { path: '/js/main.js', as: 'script' } ] criticalResources.forEach((resource) => { ctx.tags.push({ tag: 'link', props: { rel: 'preload', href: resource.path, as: resource.as, crossorigin: resource.as === 'font' ? 'anonymous' : undefined } }) }) } // Remove client-only script tags during SSR ctx.tags = ctx.tags.filter((tag) => { if (tag.tag === 'script' && tag.props.type === 'application/json') { // Keep JSON data scripts for hydration return true } if (tag.tag === 'script' && tag.props['data-client-only']) { // Remove client-only scripts during SSR return false } return true }) } } }) ``` ### Internationalization Support Handle internationalization (i18n) aspects in server rendering: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' export const i18nSsrPlugin = defineHeadPlugin({ hooks: { 'ssr:render': (ctx) => { // Get current locale from your i18n system const currentLocale = getCurrentLocale() // Your locale detection logic const defaultLocale = getDefaultLocale() // Find existing language tags const htmlLangTag = ctx.tags.find(tag => tag.tag === 'htmlAttrs' && tag.props.lang ) // Update or add language attributes if (htmlLangTag) { htmlLangTag.props.lang = currentLocale } else { // Add lang attribute to html tag ctx.tags.push({ tag: 'htmlAttrs', props: { lang: currentLocale } }) } // Add language alternates for SEO const supportedLocales = getSupportedLocales() // Your locales list const currentPath = getCurrentPath() // Current request path supportedLocales.forEach((locale) => { // Generate localized URL const localizedUrl = generateLocalizedUrl(currentPath, locale) // Add hreflang link ctx.tags.push({ tag: 'link', props: { rel: 'alternate', hreflang: locale, href: localizedUrl } }) }) // Add x-default hreflang ctx.tags.push({ tag: 'link', props: { rel: 'alternate', hreflang: 'x-default', href: generateLocalizedUrl(currentPath, defaultLocale) } }) } } }) ```