diff --git a/docs/mini-apps/technical-guides/dynamic-embeds.mdx b/docs/mini-apps/technical-guides/dynamic-embeds.mdx
index 539f4fef..afc478ca 100644
--- a/docs/mini-apps/technical-guides/dynamic-embeds.mdx
+++ b/docs/mini-apps/technical-guides/dynamic-embeds.mdx
@@ -191,6 +191,141 @@ Click the share button in your app to test the full experience. You should see t
+## Understanding Next.js Dynamic Routes
+
+When building share pages, it's important to understand how Next.js App Router handles dynamic routes to avoid common pitfalls.
+
+### How Dynamic Routes Work
+
+A dynamic route uses brackets `[param]` to match any value:
+
+```plaintext
+app/share/[username]/page.tsx
+```
+
+This route matches:
+- `/share/alice` → `{ username: "alice" }`
+- `/share/bob` → `{ username: "bob" }`
+- `/share/0x1234...` → `{ username: "0x1234..." }`
+
+### Common Pitfall: Multiple Dynamic Routes
+
+
+A common mistake is creating multiple dynamic route segments at the same directory level. This causes routing conflicts that break your embeds.
+
+
+```plaintext
+❌ This causes routing conflicts:
+app/share/[id]/page.tsx # Matches /share/123
+app/share/[username]/page.tsx # Also matches /share/123
+app/share/[wallet]/page.tsx # Also matches /share/123
+```
+
+**Why this breaks:** Next.js App Router cannot distinguish between `[id]`, `[username]`, and `[wallet]` since they all match `/share/{anything}`. The result:
+
+- **Unpredictable routing** - Next.js picks one route arbitrarily
+- **Broken embed previews** - Wrong metadata gets served to Farcaster
+- **Silent failures** - No build errors, issues only appear at runtime
+- **Debugging difficulty** - May work in development, fail in production
+
+### Solution 1: Single Dynamic Route with Type Detection
+
+Use one dynamic route that detects the parameter type:
+
+```tsx lines expandable wrap app/share/[param]/page.tsx
+import { Metadata } from 'next';
+
+interface PageProps {
+ params: Promise<{ param: string }>;
+}
+
+export async function generateMetadata({ params }: PageProps): Promise {
+ const { param } = await params;
+
+ // Detect wallet address (0x + 40 hex characters)
+ if (param.startsWith('0x') && param.length === 42) {
+ return generateWalletMetadata(param);
+ }
+
+ // Detect numeric ID
+ if (/^\d+$/.test(param)) {
+ return generateIdMetadata(param);
+ }
+
+ // Default to username
+ return generateUsernameMetadata(param);
+}
+
+async function generateWalletMetadata(wallet: string): Promise {
+ const imageUrl = `${process.env.NEXT_PUBLIC_URL}/api/og/${wallet}`;
+ return {
+ title: 'My NFT',
+ other: {
+ 'fc:miniapp': JSON.stringify({
+ version: '1',
+ imageUrl,
+ button: {
+ title: 'View NFT',
+ action: {
+ type: 'launch_frame',
+ name: 'Launch App',
+ url: process.env.NEXT_PUBLIC_URL
+ }
+ }
+ })
+ }
+ };
+}
+
+async function generateIdMetadata(id: string): Promise {
+ // Fetch post/item data by ID and return metadata
+ // ...
+}
+
+async function generateUsernameMetadata(username: string): Promise {
+ // Fetch user profile data and return metadata
+ // ...
+}
+```
+
+### Solution 2: Use Distinct Path Prefixes
+
+If type detection is complex, use different URL prefixes:
+
+```plaintext
+✅ Clear, unambiguous routes:
+app/share/user/[username]/page.tsx # /share/user/alice
+app/share/wallet/[address]/page.tsx # /share/wallet/0x1234...
+app/share/post/[id]/page.tsx # /share/post/123
+```
+
+This makes URLs longer but avoids all ambiguity.
+
+### Dynamic Base URL
+
+When deploying to multiple environments (staging, production), use `headers()` to get the actual request URL instead of hardcoding:
+
+```tsx lines wrap
+import { headers } from 'next/headers';
+
+async function getBaseUrl(): Promise {
+ const headersList = await headers();
+ const host = headersList.get('host');
+ const protocol = headersList.get('x-forwarded-proto') || 'https';
+ return host ? `${protocol}://${host}` : 'https://your-app.com';
+}
+
+export async function generateMetadata({ params }: PageProps): Promise {
+ const { wallet } = await params;
+ const baseUrl = await getBaseUrl();
+ const imageUrl = `${baseUrl}/api/og/${wallet}`;
+
+ // Use baseUrl for all URLs in metadata...
+}
+```
+
+This ensures your embed URLs work correctly in both staging (`your-app-staging.vercel.app`) and production (`your-app.com`).
+
## Related Concepts