Build a YouTube feed in React that survives a failed request.
A creator homepage should still show useful videos when YouTube is slow. This site starts with a saved list of seven uploads, renders that list into HTML, and refreshes it in the browser.
What you’ll need
- A current Node.js LTS release that satisfies the repository’s Vite requirements, npm, and Git.
- Basic JavaScript and React familiarity. A coding assistant can explain the source, but you should still inspect and run the changes.
- No API key for the saved example. A live feed for your own channel can use public RSS, or a server-side YouTube Data API key for richer metadata.
The saved example runs locally without buying a course or an AI subscription. Live hosting and provider usage may cost money; check the plans you choose.
Run the working example
git clone https://github.com/mikeholp87/ai-income-lab.git
cd ai-income-lab
npm ci
npm run devOpen the local URL printed by Vite. The featured card should show a title, thumbnail, publication date, and a link to YouTube before you click Play. The browser player is deliberately loaded only after that click.
Follow the data
src/youtube-snapshot.jsonholds the saved videos and channel counts.scripts/refresh-videos.jsrefreshes the snapshot at build time. If the public endpoint fails, a validated saved snapshot remains available.scripts/prerender.jsrenders the homepage into HTML. Video links are therefore available before browser JavaScript runs.useYouTubeFeedinsrc/main.jsxinitializes from that same snapshot and asks/api/youtubefor fresh data.api/youtube.jstalks to YouTube and caches successful results. An API key, when used, stays on the server.
Keep a useful fallback
The essential React pattern is small. Initialize from data you already have, validate the replacement, and keep the saved list when refreshing fails:
const [feed, setFeed] = useState(savedFeed);
useEffect(() => {
fetch('/api/youtube')
.then(response => {
if (!response.ok) throw new Error('Feed unavailable');
return response.json();
})
.then(next => {
if (validFeed(next)) setFeed(next);
})
.catch(() => {}); // The saved videos remain visible.
}, []);Use the repository’s validFeed helper: it checks video IDs, dates, titles, summaries, and nonnegative view counts. Don’t place arbitrary API strings into HTML with innerHTML; render text through React.
Adapt it to your channel
Change channelUrl and channelId in src/youtube.js. Replace the saved JSON with your own public video data and point the refresh script at your own feed endpoint. The sample snapshot and refresh URL belong to AI Automation Station; changing only the visible channel name would leave the wrong videos in the build.
If you use a YouTube API key, configure YOUTUBE_API_KEY on the server. Do not prefix it with VITE_ or put it in the snapshot. Keep each card’s width and height defined, provide a useful accessible Play label, and size thumbnail downloads for the viewport.
Check the result
npm test
npm run build
npm run preview- View the built page source and look for
youtube.com/watch?v=links. - Block
/api/youtubein browser developer tools and reload. The saved video cards should remain visible. - Tab to Play, activate it, and confirm the player appears. The iframe should not be loaded beforehand.
- Check a 320px viewport for clipped titles and horizontal scrolling.
Success means a readable, clickable feed survives a failed refresh. A cached snapshot is not a promise of real-time counts; this implementation refreshes live data daily.
When a check fails
If the local feed endpoint returns not found under Vite, the saved videos should still render: npm run dev does not run the Vercel API functions. If the build reports an invalid snapshot, replace it with a validated feed before retrying. If a fork shows this channel’s videos, update both the saved JSON and the refresh endpoint.
To check the pure data helpers without a network request, run node --test src/youtube.test.js. A passing test verifies the sample inputs; it does not prove that a third-party service is available.
Source and next step
Inspect the project source or see the feed on the homepage. Next, measure clicks after consent without treating a watch link as a subscription.