diff --git a/app/api/og-image/route.tsx b/app/api/og-image/route.tsx
new file mode 100644
index 0000000..1bd4cbe
--- /dev/null
+++ b/app/api/og-image/route.tsx
@@ -0,0 +1,63 @@
+import {ImageResponse} from 'next/og'
+
+export const runtime = 'edge'
+
+const font = fetch(new URL('/assets/Inter.ttf', import.meta.url)).then(
+    (res) => res.arrayBuffer()
+)
+
+const gradients = [
+    'radial-gradient(at right top, rgb(221, 214, 254), rgb(239, 68, 68), rgb(251, 146, 60))',
+    'radial-gradient(at right bottom, rgb(255, 255, 255), rgb(244, 114, 182), rgb(240, 171, 252))',
+    'radial-gradient(at left bottom, rgb(254, 202, 202), rgb(8, 145, 178), rgb(236, 252, 203))',
+    'radial-gradient(at left top, rgb(124, 58, 237), rgb(220, 252, 231), rgb(31, 41, 55))',
+    'radial-gradient(at left bottom, rgb(214, 211, 209), rgb(190, 242, 100), rgb(190, 242, 100))'
+]
+
+export async function GET(request: Request) {
+    const fontData = await font
+    const {searchParams} = new URL(request.url)
+    const title = searchParams.get('title')
+
+    return new ImageResponse(
+        (
+            
+        ),
+        {
+            width: 1200,
+            height: 600,
+            fonts: [
+                {
+                    name: 'Inter',
+                    data: fontData,
+                    style: 'normal'
+                }
+            ]
+        }
+    );
+}
\ No newline at end of file
diff --git a/app/layout.tsx b/app/layout.tsx
index 4e773bd..5f51b5d 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -7,7 +7,11 @@ import '@/styles/tailwind.css'
 
 export const metadata = {
     title: 'Ryan Freeman - Full-stack software engineer from Dublin, Ireland.',
-    description: 'Full-stack software engineer who enjoys building cloud-native applications.'
+    description: 'Full-stack software engineer who enjoys building cloud-native applications.',
+    metadataBase: new URL('https://ryanfreeman.dev'),
+    alternates: {
+        canonical: '/'
+    }
 }
 
 export default function RootLayout({children}: { children: ReactNode }) {
diff --git a/app/services/page.tsx b/app/services/page.tsx
index 3d90d4a..3edba97 100644
--- a/app/services/page.tsx
+++ b/app/services/page.tsx
@@ -10,10 +10,28 @@ import {EmailIcon} from '@/components/icons/EmailIcon'
 import {RocketIcon} from '@/components/icons/RocketIcon'
 import {ShoppingBagIcon} from '@/components/icons/ShoppingBagIcon'
 
-export const metadata = {
+const meta = {
     title: 'Services - Ryan Freeman',
+    heading: 'I offer a wide range of digital services to elevate and transform your business',
     description: 'Whether you need a WordPress website, React app, AWS support or odd coding jobs, I\'m here to help. ' +
-        'As an experienced software engineer, I produce high-quality software that will deliver immediate value for you and your customers.'
+        'As an experienced software engineer, I produce high-quality software that will deliver immediate value for you and your customers.',
+}
+
+export const metadata = {
+    ...meta,
+    openGraph: {
+        title: meta.title,
+        description: meta.description,
+        images: [
+            {
+                url: `/api/og-image?title=${meta.heading}`,
+                width: 1200,
+                height: 600,
+                alt: meta.heading,
+                type: 'image/png'
+            }
+        ]
+    }
 }
 
 type Services = {
diff --git a/assets/Inter.ttf b/assets/Inter.ttf
new file mode 100644
index 0000000..053185e
Binary files /dev/null and b/assets/Inter.ttf differ
diff --git a/components/icons/CloudIcon.tsx b/components/icons/CloudIcon.tsx
index 30f095d..be59d4a 100644
--- a/components/icons/CloudIcon.tsx
+++ b/components/icons/CloudIcon.tsx
@@ -4,7 +4,7 @@ export function CloudIcon(props: Props) {
     return (
         
     )