Helping Googlebot - Links your pages to each other - Googlebot doesn’t click on stuffs, use links! - Do not use hash URLs (/#products) - Exclude low quality / thin content - Create a sitemap
ngOnInit() { this.meta.updateTag({ name: 'robots', content: ‘noindex’ }); ... } export class HiddenPageComponent { } Exclude content from Index Set page title Inject title & meta services constructor(private title: Title, private meta: Meta) {}
Use robots.txt to prevent crawling User-agent: Googlebot Disallow: /private Everything under /private will not be crawled. *will not crawl, but might be indexed
Static Prerendering cli build --prod Generate files to dist/ Open browser Browse & Save each route as .html Deploy all files to server Generate static html pages = Prerendering Local serve dist/
Static Prerendering cli build --prod Generate files to dist/ Program Puppeteer Browse & Save each route as .html Deploy all files to server Automate with Puppeteer Local serve dist/
Static Prerendering cli build --prod Generate files to dist/ Program Puppeteer Browse & Save each route as .html Deploy all files to server Find an even easier library to help us! Local serve dist/
SSR / Dynamic (puppeteer, rendertron) Static (prerender-spa-plugin) - Rapid changing content that always change (e.g. news) - Require a server - Dynamic Rendering is a workaround - SSR increase complexity* - Predictable content (e.g. company site, event site) - Can host in cloud storage (S3, Firebase hosting)
No index when result not found fetch('/api/speakers/jane-doe') .then(res => res.json) .then(speaker => { if (!speaker.exists) this.meta.updateTag({ name: 'robots', content: 'noindex' }); });
Page B won’t be indexed // script on page A userAgreesGDPRbutton.addEventListener('click', () => { writeCookies('gdpr_agreed', true); }); // script on page B if (!readCookies('gdpr_agreed') { window.location.href='/page-a'; }
Handle feature detection if ('geolocation' in navigator) { // load content once we get location info navigator.geolocation.getCurrentPosition(loadContent); } else { // load fallback content } Uh oh, feature supported but rejected
Handle feature detection if ('geolocation' in navigator) { // load content once we get location info navigator.geolocation.getCurrentPosition( loadLocalContent, loadFallbackContent); } else { // load fallback content } Load fallback content
SEO Audits - HTTP header responses - Correct meta tags, hreflang & descriptive link text - Tap targets sizing - Checking robots.txt - Coming soon: Structured data
Useful resources & references - Headless Chrome: an answer to server-side rendering JS sites (link) - Prerendering explained (link) - Get started with dynamic rendering (link) - Google search resources (link) - Rendering on the web (link) - Javascript SEO video series (link) - Technical SEO demystified (link) Office-hours hangouts with the webmaster teams - https://www.google.com/webmasters/connect/