A simple, lightweight React component library for embedding content via Embedly's OEmbed API in Next.js applications.
- β Simple React component for rendering embeds
- β Full TypeScript support with comprehensive types
- β Server-side API utility for secure key handling
- β Supports all OEmbed types (video, photo, rich, link)
- β Customizable loading and error states
- β Works with both App Router and Pages Router
- β Zero dependencies (except React and Next.js peer deps)
npm install @embedly/nextjsSign up at embed.ly and get your API key.
Create a .env.local file in your Next.js project:
EMBEDLY_API_KEY=your_api_key_hereThe API key must be kept server-side for security. Create an API route to proxy requests to Embedly.
Create app/api/embedly/route.ts:
import { NextRequest, NextResponse } from 'next/server';
import { fetchEmbedlyData } from '@embedly/nextjs';
export async function GET(request: NextRequest) {
const apiKey = process.env.EMBEDLY_API_KEY;
if (!apiKey) {
return NextResponse.json(
{ error: 'Embedly API key not configured' },
{ status: 500 }
);
}
const searchParams = request.nextUrl.searchParams;
const url = searchParams.get('url');
if (!url) {
return NextResponse.json(
{ error: 'URL parameter is required' },
{ status: 400 }
);
}
try {
const embedData = await fetchEmbedlyData(apiKey, {
url,
maxWidth: searchParams.get('maxWidth')
? parseInt(searchParams.get('maxWidth')!, 10)
: undefined,
maxHeight: searchParams.get('maxHeight')
? parseInt(searchParams.get('maxHeight')!, 10)
: undefined,
});
return NextResponse.json(embedData);
} catch (error) {
return NextResponse.json(
{ error: error instanceof Error ? error.message : 'Failed to fetch embed data' },
{ status: 500 }
);
}
}Create pages/api/embedly.ts:
import type { NextApiRequest, NextApiResponse } from 'next';
import { fetchEmbedlyData, OEmbedResponse } from '@embedly/nextjs';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<OEmbedResponse | { error: string }>
) {
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Method not allowed' });
}
const apiKey = process.env.EMBEDLY_API_KEY;
if (!apiKey) {
return res.status(500).json({ error: 'Embedly API key not configured' });
}
const { url, maxWidth, maxHeight } = req.query;
if (!url || typeof url !== 'string') {
return res.status(400).json({ error: 'URL parameter is required' });
}
try {
const embedData = await fetchEmbedlyData(apiKey, {
url,
maxWidth: maxWidth ? parseInt(maxWidth as string, 10) : undefined,
maxHeight: maxHeight ? parseInt(maxHeight as string, 10) : undefined,
});
return res.status(200).json(embedData);
} catch (error) {
return res.status(500).json({
error: error instanceof Error ? error.message : 'Failed to fetch embed data',
});
}
}import { EmbedlyEmbed } from '@embedly/nextjs';
export default function MyPage() {
return (
<div>
<h1>Check out this video!</h1>
<EmbedlyEmbed url="https://www.youtube.com/watch?v=dQw4w9WgXcQ" />
</div>
);
}The main React component for rendering embeds.
| Prop | Type | Default | Description |
|---|---|---|---|
url |
string |
Required | The URL to embed |
apiEndpoint |
string |
/api/embedly |
Your Next.js API route endpoint |
maxWidth |
number |
undefined |
Maximum width for the embed |
maxHeight |
number |
undefined |
Maximum height for the embed |
loading |
ReactNode |
Loading message | Custom loading component |
error |
(error: Error) => ReactNode |
Error message | Custom error renderer |
onLoad |
(data: OEmbedResponse) => void |
undefined |
Callback when data loads |
onError |
(error: Error) => void |
undefined |
Callback when error occurs |
className |
string |
undefined |
Additional CSS class |
style |
CSSProperties |
undefined |
Additional inline styles |
Server-side utility function for fetching OEmbed data.
async function fetchEmbedlyData(
apiKey: string,
options: EmbedlyFetchOptions
): Promise<OEmbedResponse>apiKey: Your Embedly API key (keep this secret!)options.url: The URL to fetch embed data foroptions.maxWidth: (optional) Maximum width constraintoptions.maxHeight: (optional) Maximum height constraint
<EmbedlyEmbed url="https://www.youtube.com/watch?v=dQw4w9WgXcQ" /><EmbedlyEmbed
url="https://vimeo.com/76979871"
loading={<Spinner />}
error={(err) => <ErrorMessage message={err.message} />}
/><EmbedlyEmbed
url="https://www.flickr.com/photos/example/123456789"
maxWidth={600}
maxHeight={400}
/><EmbedlyEmbed
url="https://twitter.com/username/status/123456789"
onLoad={(data) => {
console.log('Embed type:', data.type);
console.log('Provider:', data.provider_name);
}}
onError={(err) => {
console.error('Failed to load embed:', err);
}}
/><EmbedlyEmbed
url="https://soundcloud.com/artist/track"
className="my-embed"
style={{
marginTop: '2rem',
padding: '1rem',
border: '1px solid #ccc',
}}
/>Embedly supports over 1000 content providers including:
- YouTube, Vimeo, Dailymotion
- Twitter, Instagram, Facebook
- SoundCloud, Spotify
- Flickr, Imgur
- And many more!
See the full provider list.
This library is written in TypeScript and includes comprehensive type definitions:
import type {
OEmbedResponse,
OEmbedVideoResponse,
OEmbedPhotoResponse,
OEmbedRichResponse,
OEmbedLinkResponse,
EmbedlyFetchOptions,
} from '@embedly/nextjs';Important: Never expose your Embedly API key to the client-side. Always use it server-side in your API routes.
The library is designed with security in mind:
- API key is only used server-side
- Client component communicates through your Next.js API route
- No direct client-to-Embedly API calls
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
- π Bug Reports: Open an issue on GitHub
- π¬ Discussions: Start a discussion
- π§ Pull Requests: Contributions are welcome! See CONTRIBUTING.md
- π§ Email: support@embed.ly
- π API Documentation: docs.embed.ly/reference/embedly-api
- π Get API Key: embed.ly/signup