Panduan Angular SEO
cara membuat Angular apps dapat di-crawl dan dapat diindeks — @angular/ssr vs prerendering vs hybrid rendering, hydration, judul/Meta services, History API routing, dan testing apa Googlebot sebenarnya renders.
Bahasa
Angular SEO adalah benar-benar satu decision: sajikan nyata HTML alih-alih sebuah client-dirender shell. Modern Angular (v17+) membangun SSR ke CLI sebagai @angular/ssr — prerender static routes, server-render dynamic ones, hydrate so HTML tidak thrown away. lalu melakukan basics: unique judul/deskripsi melalui Angular's judul dan Meta services, HTML5 History routing (tidak pernah hash URLs), nyata <a href> tautan, dan verify dengan pemeriksaan URL. Dynamic rendering adalah sebuah workaround, tidak sebuah strategy — dan AngularJS adalah sebuah berbeda kerangka kerja.
TL;DR — Angular membangun halaman di browser dengan JavaScript oleh default, so mentah HTML sebuah mesin pencari pertama sees adalah nearly empty. perbaiki adalah untuk kirim nyata, finished HTML alih-alih — menggunakan Angular’s dibangun-di rendering sisi server (
@angular/ssr) atau prerendering. lalu tangani basics: sebuah unique judul dan deskripsi pada setiap halaman, bersih URLs (Tidak#), dan nyata<a href>tautan.
masalah di satu kalimat
sebuah default Angular app mengirim browser sebuah tiny HTML shell — basically satu empty
<div> — plus sebuah big bundle dari JavaScript. Anda browser berjalan itu JavaScript dan
lalu halaman fills di dengan konten. itu’s called rendering sisi klien (CSR).
trouble: ketika sebuah mesin pencari pertama downloads itu URL, ini sees empty shell. Google dapat jalankan JavaScript untuk see nyata konten, tetapi ini melakukan itu kemudian, di sebuah terpisah langkah, dan tidak selalu reliably. Evidence for this claim Google can render JavaScript but processes rendering as a stage after crawling. Scope: Google Search rendering; other crawler behavior is not covered by this record. Confidence: high · Verified: Google: JavaScript SEO basics lainnya crawler — Bing, dan bot behind social previews — sering dapat’t jalankan JavaScript di semua. So mereka see tidak ada apa pun.
perbaiki: kirim finished HTML
alih-alih membuat browser (atau crawler) bangun halaman, Anda bangun ini ahead dari time atau pada sebuah server dan kirim menyelesaikan HTML. Angular memberikan Anda dua main cara:
- rendering sisi server (SSR) — sebuah server berjalan Angular untuk setiap permintaan dan mengirim back penuh halaman. baik untuk konten itu perubahan sering. Evidence for this claim Angular supports server-side rendering and build-time prerendering through its SSR tooling. Scope: Current Angular SSR and prerender features. Confidence: high · Verified: Angular: Server-side and hybrid rendering
- Prerendering — Angular membangun static HTML files untuk Anda halaman di bangun time, so ada Tidak server needed. Fastest option, great untuk blog posts dan marketing halaman.
Modern Angular (versi 17 dan up) membangun keduanya dari ini right ke toolkit. Anda tambahkan
ini dengan satu command: ng add @angular/ssr. (Anda dapat memiliki heard old name Angular
Universal — itu adalah yang sama idea sebagai sebuah terpisah tambahkan-pada. Angular folded ini ke
core di v17 dan renamed ini.)
lainnya basics
- Memberikan setiap halaman sebuah unique judul dan deskripsi. Angular tidak akan melakukan ini untuk Anda —
Anda set them di code menggunakan Angular’s dibangun-di
TitledanMetaservices. Tanpa ini, setiap halaman shares satu judul. - gunakan bersih URLs, tidak hash URLs. Angular’s default routing membuat nice URLs like
/products/shoes. hindari older “hash” (terjemahan) “hash” style (/#/products) — mesin pencari dapat’t reliably tangani bagian setelah#. - gunakan nyata tautan. Navigation memiliki untuk menjadi nyata
<a href>tautan, tidak buttons atau click handlers, atau Google dapat’t ikuti them.
hal sebagian besar orang mendapatkan wrong
“Google tidak dapat index Angular” (terjemahan) “Google dapat’t indeks Angular” adalah sebuah myth — ini dapat render JavaScript. tetapi ini adalah lebih lambat dan lebih sedikit reliable daripada hanya sending nyata HTML, dan non-Google crawler dapat’t melakukan ini di semua. So untuk apa pun Anda ingin ditemukan, render pada server atau prerender ini.
ingin deeper versi — hybrid rendering per route, hydration, SEO services dengan code, dan cara test apa Google sebenarnya sees? Switch untuk Advanced tab.
Evidence for this claim Modern Angular documents @angular/ssr as its server-side and hybrid rendering package. Scope: Current Angular documentation; historical Angular Universal details are not required for this claim. Confidence: high · Verified: Angular: Server-side and hybrid renderingTL;DR — Angular SEO adalah satu architectural decision wearing sebuah lot dari hats: mendapatkan nyata HTML ke respons alih-alih sebuah client-dirender shell. Modern Angular (v17+) membangun SSR ke CLI sebagai
@angular/ssr( rebranded, integrated successor untuk Angular Universal). Prerender static routes, server-render dynamic ones, mix them dengan hybrid rendering, dan hydrate so server HTML adalah reused tidak rebuilt. lalu melakukan blocking-dan-tackling: unique judul/deskripsi melaluiTitle/Metaservices (atau router’sTitleStrategy), HTML5 History routing — tidak pernahHashLocationStrategy— nyata<a href>tautan, JSON-LD injected safely, dan verification melalui URL Inspection. Dynamic rendering adalah sebuah Google-acknowledged workaround, tidak sebuah strategy.
default adalah masalah: rendering sisi klien
sebuah stock Angular bangun ships sebuah index.html milik siapa body adalah essentially <app-root></app-root>
plus script tags. Tanpa executing JavaScript, sebuah crawler sees Tidak heading, Tidak copy, Tidak
tautan — konten adalah assembled di browser setelah bundle memuat. ini adalah yang sama
core issue I deskripsikan di JavaScript SEO:
web moved off plain HTML, dan CSR adalah riskiest end dari itu spectrum.
(ini guide’s implementation detail — RenderMode APIs, hydrate triggers, event replay — reflect Angular v22. versi-spesifik fitur di bawah adalah dated: v17 SSR rename, v18 event replay, v19–v20 incremental hydration.)
CSR membuat three distinct SEO masalah:
- Delayed, lebih sedikit-reliable pengindeksan. Google memproses JS apps di three phases — “Crawling, Rendering, dan Indexing” (terjemahan) “crawling, rendering, dan pengindeksan” — dan rendering adalah deferred ke sebuah queue. Anda konten tidak exist untuk pengindeksan until itu render berjalan.
- Worse Core Web Vitals. LCP suffers karena browser harus download dan execute sebuah bundle sebelum painting bermakna konten.
- Non-Google crawler see shell. Bingbot adalah far lebih sedikit consistent di JS rendering, dan social/tautan-preview bot umumnya jangan render di semua — so Open Graph tags dan konten injected client-side tidak pernah reach them.
Bagaimana Googlebot sebenarnya menangani sebuah Angular app
Googlebot adalah evergreen — ini renders dengan sebuah saat ini versi dari Chrome’s V8 mesin dan memperbarui alongside Chrome releases. Evidence for this claim Googlebot uses an evergreen version of Chromium for rendering. Scope: Google Search rendering engine; this does not remove application-level rendering risks. Confidence: high · Verified: Google: Evergreen Googlebot So ini dapat jalankan Angular. tetapi perilaku memiliki hard edges worth designing sekitar:
- rendering adalah queued, tidak immediate. Google documents distinct crawling, rendering, dan pengindeksan phases dan tidak publish sebuah fixed timetable untuk bagaimana panjang rendering langkah takes untuk catch up untuk crawling. industry shorthand untuk ini adalah “dua waves” (terjemahan) “dua waves” — mentah HTML terindeks pertama (sebuah blank shell untuk CSR Angular), dirender DOM terindeks kemudian, setiap kali itu render berjalan. SSR/prerendering sidesteps tunggu: HTML adalah menyelesaikan pada pertama fetch, so ada Tidak terpisah render lulus untuk itu konten untuk tunggu pada.
- ** renderer adalah stateless.** Tidak cookies, Tidak
localStorage, TidaksessionStoragecarried antara memuat; ini declines permission prompts. jangan gate konten pada client state. - ini tidak click atau scroll, dan ini renders di sebuah very tall viewport. konten behind sebuah interaction tidak akan menjadi seen.
- Resources adalah cached aggressively — gunakan konten-fingerprinted filenames (Angular’s
default
main.<hash>.js) so diperbarui bundles tidak disajikan stale.
@angular/ssr — apa ini adalah dan naming history
rendering sisi server berjalan Angular pada sebuah Node server per permintaan dan mengembalikan fully dirender HTML, yang browser lalu hydrates (attaches event listeners untuk existing DOM alih-alih re-rendering). setiap crawler — Googlebot, Bingbot, social bot — mendapatkan menyelesaikan HTML pada pertama permintaan, Tidak kedua wave diperlukan.
naming trips orang up, so menjadi precise: “Angular Universal” (terjemahan) “Angular Universal” adalah historical SSR
solusi, shipped sebagai sebuah external package (@nguniversal/express-engine). dengan Angular
v17 (November 2023), SSR adalah integrated secara langsung ke Angular CLI dan Application
Builder dan renamed @angular/ssr; Angular Universal repository adalah now di
maintenance mode. Evidence for this claim Modern Angular documents @angular/ssr as its server-side and hybrid rendering package. Scope: Current Angular documentation; historical Angular Universal details are not required for this claim. Confidence: high · Verified: Angular: Server-side and hybrid rendering setup adalah now sebuah satu-liner:
# New project with SSR enabled
ng new my-app --ssr
# Add SSR to an existing project
ng add @angular/ssrini replaces old ng add @nguniversal/express-engine. sama idea, pertama-class tooling.
Prerendering (static generation / SSG)
Prerendering generates static HTML untuk routes di bangun time, so Tidak server berjalan di
permintaan time — Anda dapat deploy untuk sebuah CDN. ini memberikan fastest TTFB/FCP/LCP dan lowest
operational cost. di v17+ Anda configure ini per route melalui sebuah server routes file
(app.routes.server.ts) menggunakan RenderMode.Prerender, dan outputMode: 'static' produces
sebuah fully static app.
constraint: data harus menjadi tersedia di bangun time, ada Tidak per-pengguna konten, dan very besar situs berarti slow membangun. ini adalah ideal untuk marketing halaman, docs, dan blog posts — persis konten itu sebagian besar perlu untuk peringkat dan menjadi cited.
Hybrid rendering — choose sebuah mode per route
big v17+ advancement adalah itu rendering mode adalah sebuah per-route decision, configured di
app.routes.server.ts:
RenderMode.Prerender— static routes (home, tentang, blog posts).RenderMode.Server— dynamic, per-permintaan routes (hasil pencarian, dashboards dengan fresh data).RenderMode.Client— internal-hanya routes Anda tidak ingin terindeks anyway (admin UIs, authenticated-hanya screens). CSR adalah genuinely fine di sini.
ini adalah decision aturan dalam praktik: prerender apa static, server-render apa harus menjadi fresh, dan hanya fall back untuk client rendering untuk hal itu tidak seharusnya menjadi di indeks.
Hydration — dan pitfall itu wrecks CLS
Naive SSR memiliki sebuah flaw: server mengirim HTML, lalu browser throws ini away dan
re-renders dari scratch, causing sebuah flash dan wasted berfungsi. Hydration memperbaiki itu —
browser restores server-dirender app dan reuses matching DOM alih-alih destroying
dan recreating ini, hanya wiring up interactivity. Enable ini di app.config.ts:
provideClientHydration()Prerequisite: hydration adalah sebuah client-side companion untuk SSR, tidak sebuah standalone switch.
provideClientHydration() hanya melakukan sesuatu pada sebuah route itu’s sudah server-dirender
(atau prerendered) — ini dapat’t turn sebuah RenderMode.Client route’s shell ke server HTML.
Enable SSR/prerendering untuk route pertama.
Dua newer capabilities penting untuk SEO-berdekatan UX — neither perubahan Penelusuran pengindeksan:
- Event replay (v18+): captures didukung pengguna interactions itu happen sebelum hydration finishes dan replays them setelah ini menyelesaikan. ini reduces lost clicks untuk interaction jenis ini mendukung; ini adalah sebuah UX/interactivity fitur, tidak sebuah SEO satu, dan ini memiliki Tidak effect pada apa Google indeks.
- Incremental hydration (v19 developer preview, stable di v20): bergantung pada SSR,
hydration, deferrable views, dan event replay together — ini tidak sebuah standalone fitur.
ini adalah powered oleh
@deferblocks dengan hydrate triggers itu control yang boundaries stay dehydrated pada awal render; sebuahhydrate neverboundary tetap dehydrated pada pertama muat tetapi tidak niscaya blocked dari memuat -nya dependencies pada kemudian client-side renders (e.g., setelah sebuah route perubahan). SEO-relevant effect adalah indirect: lebih sedikit JavaScript hydrated upfront dapat help LCP, tetapi trigger config adalah sebuah rendering detail, tidak sebuah crawler-timing mechanism.
** critical pitfall:** putting @if (isPlatformBrowser(...)) secara langsung di sebuah template
penyebab server dan client untuk render berbeda markup — sebuah hydration mismatch — yang
produces layout shift dan damages CLS. gunakan afterNextRender() untuk browser-hanya berfungsi
alih-alih branching template pada platform.
judul dan meta tags — Angular’s dibangun-di services
Angular dapat’t bind secara langsung untuk <title> element’s text, so Anda manage head tags melalui
dua services dari @angular/platform-browser:
Title—setTitle()/getTitle().Meta—addTag(),addTags(),updateTag(),getTag(),removeTag(), dengan selectors likename='description'atauproperty='og:title'.
Anda melakukan tidak perlu sebuah ketiga-party library untuk basics. sebuah shared SEO service adalah bersih pattern:
@Injectable({ providedIn: 'root' })
export class SeoService {
private title = inject(Title);
private meta = inject(Meta);
updatePage(title: string, description: string) {
this.title.setTitle(title);
this.meta.updateTag({ name: 'description', content: description });
this.meta.updateTag({ property: 'og:title', content: title });
}
}untuk judul secara khusus, router’s TitleStrategy (Angular v14+) lets Anda set sebuah
title secara langsung di route config so halaman judul memperbarui secara otomatis pada navigation —
Tidak per-component code. dan jangan set document.title = ... oleh hand; gunakan Title service
so ini berfungsi correctly di bawah SSR.
struktur URL
- gunakan default HTML5 History API routing (
PathLocationStrategy) — bersih URLs like/products/shoes. ini perlu<base href="/">diindex.html. - tidak pernah gunakan
HashLocationStrategy/useHash: trueuntuk publik konten. Fragment identifiers setelah#adalah stripped sebelum HTTP permintaan, so server tidak pernah sees them dan Googlebot dapat’t reliably resolve#/products— Anda seluruh situs dapat collapse untuk satu URL. - nyata
<a href>tautan untuk navigation, including untuk lazy-dimuat routes. Lazy memuat adalah fine untuk performa, tetapi tautan untuk itu routes masih memiliki untuk menjadi dapat di-crawl anchors, tidak click handlers.
data terstruktur (JSON-LD)
Google mendukung injecting JSON-LD dengan JavaScript. robust Angular pattern adalah sebuah service
itu membuat sebuah <script type="application/ld+json"> dan appends ini untuk document.head, menggunakan
Angular’s DOCUMENT injection token alih-alih touching document globally (yang breaks pada
server). pertahankan semua schema di satu place — jangan split ini antara static HTML dan
dirender DOM — dan validate dengan Rich hasil Test plus pemeriksaan URL.
Dynamic rendering — sebuah legacy workaround, tidak sebuah plan
Dynamic rendering menyajikan sebuah prerendered versi untuk bot (melalui Puppeteer, Rendertron, atau
prerender.io) dan penuh SPA untuk pengguna. Google adalah jelas itu “dynamic rendering is a
workaround and not a long-term solution,” (terjemahan) “dynamic rendering adalah workaround dan bukan solusi jangka panjang,” dan itu ada “better solutions than dynamic
rendering” (terjemahan) “solusi yang lebih baik daripada dynamic rendering” — namely rendering sisi server, static rendering, atau hydration. ini adalah tidak
secara otomatis cloaking sebagai panjang sebagai Anda sajikan substantially similar konten, tetapi ini menambahkan sebuah
extra rendering server, risks konten drift, dan melakukan tidak ada apa pun untuk pengguna nyata’ Core Web Vitals.
untuk sebuah baru Angular bangun, reach untuk @angular/ssr atau prerendering alih-alih.
umum Angular SEO mistakes
- Hash routing (
#URLs) — seluruh situs looks like satu URL. - Tidak
Title/Metapanggilan — setiap halaman shares satu judul dan deskripsi. - Tidak SSR/prerendering — konten hanya ada setelah deferred render wave.
- Blocking
.js/.cssdirobots.txt— Google dapat’t render, indeks sebuah empty shell. - Returning
200pada sebuah tidak-ditemukan view — sebuah soft 404; mengembalikan nyata404atau tambahkannoindex. document.title = ...alih-alihTitleservice.isPlatformBrowser()di dalam template@if— hydration mismatch → CLS.- Touching
window/localStorage/documentdi code itu berjalan pada server — SSR crashes. - Splitting schema antara mentah HTML dan dirender DOM.
- Testing di local dev alih-alih dengan pemeriksaan URL — relying pada assumptions, tidak Googlebot.
Testing Angular untuk SEO
- pemeriksaan URL (Search Console) adalah sumber kebenaran: di-crawl-halaman view menampilkan dirender HTML — DOM setelah Googlebot ran JavaScript, yang adalah apa mendapatkan terindeks — plus JS console messages dan blocked resources. Jalankan Pengujian langsung untuk sebuah pada-demand render.
curlURL untuk see mentah, pre-JS HTML — sebuah empty shell berarti CSR dengan Tidak SSR.- Rich hasil Test validates data terstruktur.
- Ahrefs situs Audit (JS rendering pada) dan Screaming Frog (JS mode) diff mentah vs. dirender DOM di scale.
- Lighthouse / PageSpeed Insights untuk Core Web Vitals impact dari Anda rendering pilihan.
Angular adalah tidak buruk untuk SEO — ini adalah hanya berbeda. Mendapatkan nyata HTML ke respons, manage Anda head tags, pertahankan URLs dan tautan dapat di-crawl, dan let Google’s own alat arbitrate apa dirender. ini topic sits alongside JavaScript SEO dan headless-CMS rendering pertanyaan di ini cluster — underlying lesson adalah yang sama di seluruh semua dari them: rendering mode decides hampir semuanya.
AI summary
sebuah condensed take pada Advanced versi:
- Angular’s default adalah rendering sisi klien (CSR) — sebuah near-empty HTML shell. itu berarti delayed/unreliable pengindeksan, worse LCP, dan non-Google crawler (Bing, social) seeing tidak ada apa pun.
- Googlebot adalah evergreen dan renders JS, tetapi rendering adalah queued ( “dua waves” (terjemahan) “dua waves” — mentah HTML pertama, dirender DOM kemudian, pada Tidak fixed timetable), stateless (Tidak cookies/storage), tidak click/scroll, dan caches resources hard. SSR/prerendering sidesteps tunggu — HTML adalah menyelesaikan pada pertama fetch, so ada Tidak terpisah render lulus untuk tunggu pada.
@angular/ssradalah modern perbaiki — SSR dibangun ke Angular CLI since v17, replacing externally maintained Angular Universal (@nguniversal/express-engine). Setup:ng new --ssrataung add @angular/ssr.- Prerendering (bangun-time static HTML) adalah fastest dan CDN-deployable — best untuk static marketing/blog/docs konten; limited untuk bangun-time data.
- Hybrid rendering sets mode per route di
app.routes.server.ts:RenderMode.Prerender(static),RenderMode.Server(dynamic),RenderMode.Client(non-terindeks internal halaman). - Hydration (
provideClientHydration()) reuses server HTML pada sebuah sudah-SSR/prerendered route — ini tidak buat server HTML untuk CSR. Event replay (v18+) captures didukung pre-hydration interactions dan replays them setelah; incremental hydration (v19 preview / v20 stable) bergantung pada SSR + hydration + deferrable views + event replay together, menggunakan@deferhydrate triggers untuk control yang boundaries stay dehydrated pada awal muat (hydrate nevertidak block kemudian client-side memuat). Neither perubahan Penelusuran pengindeksan. hindariisPlatformBrowser()di template@if— ini penyebab hydration mismatch → CLS; gunakanafterNextRender(). - gunakan dibangun-di
TitledanMetaservices (Tidak ketiga-party lib needed); router’sTitleStrategy(v14+) sets per-route judul secara otomatis. - gunakan HTML5 History routing, tidak pernah hash (
#) URLs; navigation harus menjadi nyata<a href>anchors. JSON-LD dapat menjadi injected melaluiDOCUMENTtoken. - Dynamic rendering adalah sebuah workaround, tidak sebuah strategy — Google recommends SSR/static/ hydration alih-alih.
- Test dengan pemeriksaan URL (dirender HTML),
curl(mentah HTML), Rich hasil Test, dan sebuah JS-rendering crawler. AngularJS ≠ Angular — old AngularJS advice tidak apply.
Dokumentasi resmi
Utama-sumber documentation dari Google dan Angular.
- memahami JavaScript SEO basics — crawl → render → indeks phases, dapat di-crawl
<a href>tautan, fragment-routing warnings, soft 404s, dan JS-injected data terstruktur. - Dynamic rendering (workaround) — mengapa ini adalah sebuah workaround, cloaking nuance, dan SSR/static/hydration alternatives.
- rendering pada Web (web.dev — Addy Osmani & Jason Miller) — canonical definitions dari SSR, CSR, static rendering, dan hydration, dan mereka performa trade-offs.
- pemeriksaan URL alat — cara see dirender HTML Google sebenarnya indeks, plus JS console messages.
Angular
- Angular — server-side dan hybrid rendering (SSR) — official
@angular/ssrguide, server routes, danRenderMode. - Angular —
Titleservice —setTitle()/getTitle(). - Angular —
Metaservice —addTag(),updateTag(), dan selectors. - Angular — Router reference —
PathLocationStrategyvs. hash routing,TitleStrategy. - Introducing Angular v17 (Angular team blog) — SSR becoming sebuah pertama-class CLI fitur.
- Angular Universal (maintenance mode) — historical package, now superseded oleh
@angular/ssr.
Quotes dari sumber
pada—record statements dari Google dan dari my own writing. setiap penelusuran-mesin tautan adalah sebuah deep tautan itu jumps untuk quoted passage pada sumber halaman.
Google — bagaimana JavaScript apps adalah processed
- “Google processes JavaScript web apps in three main phases: 1. Crawling 2. Rendering 3. Indexing.” (terjemahan) “Google memproses aplikasi web JavaScript dalam tiga fase: crawling, rendering, lalu indexing.” — Google Search Central docs. Jump untuk quote
- “Google can only discover your links if they are <a> HTML elements with an href attribute.” (terjemahan) “Google hanya dapat menemukan tautan Anda jika tautan itu adalah elemen HTML <a> dengan atribut href.” — Google Search Central docs. Jump untuk quote
Google — dynamic rendering adalah sebuah workaround
- “Dynamic rendering was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines.” (terjemahan) “Dynamic rendering adalah workaround, bukan solusi jangka panjang untuk masalah konten yang dibuat JavaScript di mesin pencari.” — Google Search Central docs. Jump untuk quote
web.dev — prefer SSR / static rendering (Addy Osmani & Jason Miller)
- “Rendering an app on the server to send HTML, rather than JavaScript, to the client.” (terjemahan) “merender aplikasi di server untuk mengirim HTML, bukan JavaScript, ke klien.” — definisi rendering sisi server. Jump untuk quote
Patrick Stox (my own berfungsi — JavaScript SEO: sebuah Definitive Guide)
- “JavaScript is not bad for SEO, and it’s not evil. It’s just different from what many SEOs are used to.” (terjemahan) “JavaScript tidak buruk untuk SEO dan bukan sesuatu yang jahat; hanya berbeda dari hal yang biasa digunakan banyak SEO.”
- “Any kind of SSR, static rendering, and prerendering setup is going to be fine for search engines.” (terjemahan) “Jenis setup SSR, rendering statis, atau prerendering apa pun akan baik untuk mesin pencari.”
Angular SEO checklist
sebuah quick lulus untuk konfirmasi sebuah Angular app adalah dapat di-crawl dan dapat diindeks:
- Publik konten adalah disajikan sebagai nyata HTML melalui
@angular/ssr(SSR) atau prerendering, tidak penuh CSR. - rendering mode adalah set per route di
app.routes.server.ts— prerender static routes, server-render dynamic ones, client-render hanya non-terindeks internal halaman. - Hydration adalah enabled (
provideClientHydration()), dan Tidak template menggunakanisPlatformBrowser()di dalam@if(gunakanafterNextRender()alih-alih). - setiap halaman sets sebuah unique judul (melalui
Titleservice atau routerTitleStrategy) dan sebuah unique deskripsi (melaluiMetaservice). - Open Graph / Twitter Card tags adalah set dengan
Metaservice untuk social previews. - Routing menggunakan HTML5 History API (default) dengan
<base href="/">— tidakHashLocationStrategy/useHash: true. - semua navigation menggunakan nyata
<a href>anchors, including tautan untuk lazy-dimuat routes. -
robots.txtmelakukan tidak block.jsatau.cssresources. - Client-side tidak-ditemukan views mengembalikan nyata
404atau carrynoindex(Tidak soft 404s). - Tidak
window/localStorage/documentaccess di code itu berjalan pada server (gunakanDOCUMENTtoken / platform guards). - JSON-LD adalah di satu place dan melewati Rich hasil Test.
- Anda verified dirender HTML di pemeriksaan URL — tidak hanya local dev.
mental models
1. Mendapatkan nyata HTML ke respons. Hampir setiap Angular SEO masalah reduces untuk satu pertanyaan: melakukan crawler mendapatkan finished HTML pada pertama fetch, atau sebuah shell ini memiliki untuk render? SSR dan prerendering jawaban “Ya.” (terjemahan) “Ya.” CSR jawaban “eventually, maybe.” (terjemahan) “eventually, maybe.” Mulai setiap audit di sini.
2. per-route rendering decision aturan.
- Static konten (home, tentang, blog, docs) →
RenderMode.Prerender. - Dynamic, harus-menjadi-fresh konten (penelusuran, langsung data) →
RenderMode.Server. - Internal/authenticated halaman Anda tidak ingin terindeks →
RenderMode.Clientadalah fine.
3. “Angular Universal” (terjemahan) “Angular Universal” dan “@angular/ssr” (terjemahan) “paket SSR Angular modern” adalah ide yang sama dari era berbeda.
Universal adalah external package; v17 absorbed SSR ke CLI dan renamed ini. jika Anda’re pada
sebuah modern Angular, Anda ingin @angular/ssr — Universal repo adalah di maintenance mode.
4. Hydrate, jangan re-render.
Naive SSR mengirim HTML dan lalu throws ini away. provideClientHydration() reuses ini — tetapi hanya
pada sebuah route itu’s sudah SSR/prerendered, ini tidak buat server HTML untuk sebuah CSR route. Event
replay dan incremental hydration (@defer) shave upfront JavaScript. tidak pernah branch sebuah template pada
isPlatformBrowser() — itu’s bagaimana Anda mendapatkan sebuah hydration mismatch dan sebuah CLS hit.
5. Head tags adalah Anda job, tidak Angular’s.
ada Tidak Yoast di sini. Set judul dan deskripsi dengan sengaja dengan Title/Meta services
(atau TitleStrategy), per halaman. “All pages share one title” (terjemahan) “semua halaman share satu judul” adalah default failure, tidak buruk luck.
6. Design untuk sebuah stateless bot pada bersih URLs.
History-API routing, nyata <a href> tautan, Tidak reliance pada cookies/storage, tanpa konten behind sebuah
click. lalu let pemeriksaan URL — tidak Anda laptop — tell Anda apa dirender.
Angular SEO — cheat sheet
rendering modes
| Mode | Di mana HTML adalah dibangun | SEO | Best untuk | Angular config |
|---|---|---|---|---|
| Prerender (SSG) | bangun time → static files | ✅ Best | Static marketing/blog/docs | RenderMode.Prerender |
| SSR | server, per permintaan | ✅ Great | Dynamic, harus-menjadi-fresh konten | RenderMode.Server / @angular/ssr |
| Client (CSR) | di browser | ⚠️ Risky | Internal/authed halaman (tidak terindeks) | RenderMode.Client |
| Dynamic rendering | Terpisah bot server | Workaround hanya | Legacy apps itu dapat’t migrate | Puppeteer / Rendertron / prerender.io |
Setup commands
| Goal | Command |
|---|---|
| baru project dengan SSR | ng new my-app --ssr |
| tambahkan SSR untuk existing app | ng add @angular/ssr |
| Enable hydration | provideClientHydration() di app.config.ts |
Head + routing fast aturan
- judul/deskripsi: Angular’s
Title+Metaservices (Tidak ketiga-party lib needed). - Auto per-route judul: router
TitleStrategy(v14+) melalui routetitleproperty. - Routing: HTML5 History API +
<base href="/">. tidak pernahuseHash: true. - tautan: nyata
<a href>anchors — bahkan untuk lazy-dimuat routes. - JSON-LD: inject melalui
DOCUMENTtoken; pertahankan ini di satu place.
Naming
- Angular Universal = old external package (
@nguniversal/express-engine), maintenance mode. @angular/ssr= yang sama SSR, dibangun ke CLI since v17.- AngularJS (v1.x) ≠ Angular (v2+) — berbeda kerangka kerja; old AngularJS advice tidak apply.
Gotchas
isPlatformBrowser()di template@if→ hydration mismatch → CLS. gunakanafterNextRender().window/localStorage/documentpada server → SSR crash.- Blocking
.js/.cssdi robots.txt → Google dapat’t render.
periksa apakah sebuah Angular app adalah sebenarnya server-dirender
fastest cara untuk know jika sebuah URL adalah CSR atau SSR/prerendered adalah untuk fetch mentah HTML (sebelum apa pun
JavaScript berjalan) dan cari Anda nyata konten. sebuah CSR Angular app mengembalikan sebuah hampir-empty
<app-root>; sebuah SSR/prerendered satu mengembalikan finished markup.
macOS / Linux
# Raw HTML as the server sends it — this is the "first fetch", pre-JS
curl -sL -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
https://example.com/page/ -o raw.html
# Is your real headline in the raw HTML? Empty result = CSR with no SSR
grep -o "Your headline text" raw.html
# A near-empty <app-root> is the tell-tale CSR signature
grep -o "<app-root></app-root>" raw.htmlWindows (PowerShell)
$ua = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
Invoke-WebRequest -Uri "https://example.com/page/" -UserAgent $ua -OutFile raw.html
Select-String -Path raw.html -Pattern "Your headline text"
Select-String -Path raw.html -Pattern "<app-root></app-root>"jika headline adalah missing dan Anda see sebuah bare <app-root>, konten bergantung pada rendering —
tambahkan SSR atau prerendering. (untuk dirender DOM, gunakan pemeriksaan URL’s “View Crawled Page →
rendered HTML” (terjemahan) “View di-crawl halaman →
dirender HTML”; sebuah plain curl dapat’t jalankan JS.)
Konfirmasi Anda tidak blocking Angular’s JS/CSS di robots.txt
macOS / Linux
curl -sL https://example.com/robots.txt | grep -iE "disallow.*\.(js|css)|Disallow:\s*/(assets|dist|main)"sebuah Disallow matching Anda bundle berarti Google dapat’t render halaman properly — hampir selalu sebuah
mistake.
alat untuk debugging Angular SEO
- pemeriksaan URL (Google Search Console) — sumber kebenaran. Jalankan sebuah Pengujian langsung, lalu baca dirender HTML ( DOM setelah Googlebot ran Anda Angular JS), screenshot, halaman resources (apa dimuat vs. apa adalah blocked), dan JavaScript console messages.
- Rich hasil Test — konfirmasi Anda JSON-LD adalah present di dirender output setelah apa pun rendering perubahan.
curl— fetch mentah, pre-JS HTML untuk tell CSR (empty<app-root>) dari SSR/prerendered.- Ahrefs situs Audit (JS rendering enabled) — melakukan crawl dengan headless Chrome dan diffs mentah vs. dirender DOM, surfacing missing metadata, rusak canonicals, dan indexability issues di scale.
- Screaming Frog SEO Spider (JS-rendering mode) — bandingkan mentah vs. dirender konten per URL.
- Lighthouse / PageSpeed Insights — mengukur Core Web Vitals impact dari Anda rendering strategy (CSR vs. SSR vs. prerender).
- Angular CLI / DevTools — konfirmasi bangun’s
outputMode, server routes, dan hydration adalah configured sebagai Anda expect.
Resources worth Anda time
My related writing
- JavaScript SEO: sebuah Definitive Guide — my penuh guide untuk rendering, DOM parity, paling-restrictive-directive aturan, dan yang rendering setups adalah safe. Angular SEO adalah sebuah spesifik application dari semuanya di sini.
- Beginner’s Guide untuk SEO teknis — di mana rendering dan crawling fit di bigger picture.
My speaking
- JavaScript SEO — Ungagged 2019 (SlideShare) — Googlebot’s stateless rendering perilaku, viewport, dan caching, plus rendering approaches dari era. (Standing disclaimer: dynamic-rendering recommendation di itu deck adalah now outdated — Google memiliki since called ini sebuah workaround.)
Dari sumber industri
- Rendering pada Web (web.dev) — tulisan kanonik Addy Osmani dan Jason Miller tentang SSR, CSR, rendering statis, dan trade-off hydration.
- Rendering sisi server dan hybrid (SSR) (angular.dev) — panduan resmi
@angular/ssrtentang server routes,RenderMode, prerendering, dan hydration. - Introducing Angular v17 (Angular team blog) — rilis itu dibuat SSR sebuah pertama-class CLI fitur dan introduced
@angular/ssrpackage. - Angular Universal (maintenance mode) (GitHub) — historical SSR package itu
@angular/ssrreplaced, berguna untuk understanding rename. - Angular SEO Guide (mesin pencari Journal, Jamie Indigo) — classic dua-wave-pengindeksan walkthrough; strong pada fundamentals though ini lebih lama dari v17 rename.
- Guide untuk Angular SSR (Angular Architects, Alexander Thalhammer, March 2025) — sebuah code-berat SSR setup guide; periksa code samples terhadap official
@angular/ssrdocs untuk API perubahan since publication. - r/TechSEO — community untuk rendering dan pengindeksan debugging.
Angular SEO anti-patterns
Concrete mistakes I see repeatedly di Angular apps — setiap satu adalah sebuah habit worth memeriksa untuk secara langsung, tidak hanya sebuah theoretical risk.
Shipping sebuah CSR-hanya bangun dan calling ini selesai
default ng new output memiliki Tidak SSR atau prerendering. ini adalah fastest cara untuk
mulai sebuah project dan easiest cara untuk end up dengan sebuah empty <app-root> pada
pertama fetch. Mengapa ini adalah wrong: mentah HTML sebuah crawler sees memiliki tanpa konten, so
pengindeksan bergantung entirely pada Google’s deferred render lulus — dan lainnya bot jangan
mendapatkan sebuah kedua chance di semua. melakukan alih-alih: tambahkan @angular/ssr di mulai dari
project (ng new my-app --ssr), atau jalankan ng add @angular/ssr pada sebuah existing satu,
sebelum Anda ship apa pun Anda ingin ditemukan.
menggunakan HashLocationStrategy untuk publik routes
Hash routing (useHash: true, URLs like /#/products/shoes) adalah masih default
di beberapa older Angular tutorials dan boilerplate. Mengapa ini adalah wrong: semuanya
setelah # adalah stripped client-side sebelum permintaan ever reaches server,
so server — dan Googlebot — hanya ever sees satu URL untuk seluruh app. melakukan
alih-alih: gunakan default HTML5 History API routing (PathLocationStrategy) dengan
<base href="/"> di index.html.
Branching sebuah template pada isPlatformBrowser()
Wrapping konten di @if (isPlatformBrowser(platformId)) feels like obvious
cara untuk guard browser-hanya code. Mengapa ini adalah wrong: server renders satu branch
dan client renders lainnya pada hydration, yang adalah sebuah hydration mismatch —
Angular memiliki untuk reconcile perbedaan, dan terlihat hasil adalah layout shift
itu menampilkan up sebagai CLS. melakukan alih-alih: gunakan afterNextRender() untuk browser-hanya berfungsi
so template itself renders identically pada server dan client.
Setting document.title secara langsung alih-alih menggunakan Title service
ini berfungsi di local dev, so ini adalah sebuah easy shortcut untuk reach untuk. Mengapa ini adalah wrong:
direct DOM access like document.title = '...' tidak play well dengan SSR —
server memiliki Tidak document global di yang sama sense browser melakukan, dan Anda lose
router-integration benefits dari Angular’s own judul menangani. melakukan alih-alih:
inject Angular’s Title service (setTitle()) atau configure judul per route dengan
router’s TitleStrategy.
Touching window, localStorage, atau document di code itu berjalan selama SSR
sebuah component atau service itu membaca localStorage atau memeriksa window.innerWidth di
construction time berfungsi fine di browser dan crashes server render.
Mengapa ini adalah wrong: none dari itu globals exist pada Node server proses berjalan
Anda SSR bangun, so render throws dan permintaan either 500s atau silently falls
back untuk sebuah empty respons. melakukan alih-alih: gate itu code behind afterNextRender()
atau inject Angular’s DOCUMENT token alih-alih global, dan test SSR bangun
locally (ng build + serving SSR output), tidak hanya ng serve.
Treating dynamic rendering sebagai sebuah permanent perbaiki
Standing up Puppeteer atau sebuah service like Rendertron untuk sajikan bot sebuah prerendered
snapshot solves immediate symptom. Mengapa ini adalah wrong: ini adalah sebuah extra sistem untuk
maintain, ini dapat drift out dari sync dengan apa pengguna nyata see, dan Google memiliki mengatakan
secara langsung itu ini adalah sebuah workaround alih-alih sebuah panjang-istilah solusi. melakukan alih-alih:
migrate untuk @angular/ssr atau prerendering so setiap requester — bot atau human — mendapatkan
yang sama nyata HTML dari yang sama pipeline.
Yang rendering mode seharusnya ini route gunakan?
Angular v17+ lets Anda set rendering mode per route di app.routes.server.ts.
pertanyaan tidak “SSR or prerender” (terjemahan) “SSR atau prerender” untuk seluruh app — ini adalah ini, ditanyakan per route.
Choosing a rendering mode for an Angular route
Prompts untuk Angular SEO berfungsi
Ready-untuk-copy prompts untuk spesifik Angular SEO tasks di ini artikel. Paste di described input dan periksa output terhadap Anda own judgment — ini save time pada mechanical bagian, mereka jangan replace testing dengan pemeriksaan URL.
1. Diff mentah vs. dirender HTML untuk sebuah route
Paste output dari curl -sL <url> (mentah HTML) dan “dirender HTML” (terjemahan) “dirender HTML” panel dari
sebuah pemeriksaan URL Pengujian langsung (atau Ahrefs/Screaming Frog JS-rendering crawl) untuk
sama URL.
Here is the raw HTML for [URL] (fetched with curl, before JavaScript runs):
[paste raw HTML]
Here is the rendered HTML for the same URL (from Google Search Console URL
Inspection's Live Test, or a JS-rendering crawler):
[paste rendered HTML]
Compare the two. List: (1) content present in rendered but missing from raw —
this is what depends on client-side rendering, (2) any <title>, meta description,
or JSON-LD that differs between the two versions, (3) whether the raw HTML shows
a near-empty <app-root> (a sign of CSR with no SSR/prerendering).Expect back sebuah pendek list dari apa CSR-dependent dan apa pun judul/meta/schema drift antara mentah dan dirender versi — dua hal worth memperbaiki pertama.
2. Review sebuah Title/Meta service implementation
Paste Anda Angular SeoService (atau equivalent) itu panggilan Title dan Meta
services.
Here is an Angular service that sets page titles and meta tags:
[paste the service's TypeScript code]
Check it against these rules: (1) titles are set via the Title service's
setTitle(), never document.title directly, (2) description is set with
meta.updateTag({ name: 'description', ... }) not addTag() (which can duplicate
the tag on repeat calls), (3) Open Graph tags use the property selector, not
name, (4) nothing in this code reads window/localStorage/document directly in a
way that would break during SSR. Flag any line that violates one of these and
suggest the fix.Expect back sebuah line-oleh-line lulus/fail terhadap itu four aturan, dengan sebuah corrected snippet untuk apa pun flagged.
3. Audit app.routes.server.ts untuk rendering-mode mistakes
Paste Anda server routes config file.
Here is my Angular app.routes.server.ts, which sets RenderMode per route:
[paste the file]
For each route, tell me: is RenderMode.Prerender used on anything that depends
on per-request or per-user data (a mistake — it would bake stale/wrong data into
the static build)? Is RenderMode.Client used on anything that looks like public,
indexable content (a missed-SEO-opportunity)? Is RenderMode.Server used on fully
static content where Prerender would be faster and cheaper? List each route with
its current mode and whether it matches the decision rule: static data →
Prerender, must-be-fresh → Server, non-indexed internal → Client.Expect back sebuah per-route verdict flagging apa pun route milik siapa RenderMode tidak
match apa route sebenarnya perlu.
Uji pemahaman Anda: Angular SEO
Five quick pertanyaan pada membuat Angular apps dapat di-crawl dan dapat diindeks. Pick sebuah jawaban untuk setiap, lalu periksa.
Log perubahan
Diperbarui 8 Agu 2026.
Ringkasan editorial dan detail perubahan yang tercatat.Detail perubahan
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
Perbandingan lengkap tidak tersedia — tidak ada cuplikan sebelumnya yang diarsipkan untuk revisi ini.
Diperbarui 17 Jul 2026.
Ringkasan editorial dan detail perubahan yang tercatat.Detail perubahan
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
-
Catatan perubahan terperinci saat ini tersedia dalam bahasa Inggris.
Perbandingan lengkap tidak tersedia — tidak ada cuplikan sebelumnya yang diarsipkan untuk revisi ini.