4. #SearchLove @goutaste
Websites Have Great Reach
11.4
4.0
Monthly Unique Visitors
Top 1k web properties vs. top 1k apps
Data: comScore Mobile Metrix Age 18+ June 2016
5. #SearchLove @goutaste
Native Apps Have Great Engagement
9.3
188.6
Average Minutes Per User
Top 1k web properties vs. top 1k apps
Data: comScore Mobile Metrix Age 18+ June 2016
6. #SearchLove @goutaste
Can We Have The Best of Both?
The REACH of
a website
The ENGAGEMENT
of an app
Image: http://bit.ly/platypus-keytar
9. #SearchLove @goutaste
What is a Progressive Web App?
Responsive Secure Fast
Downloadable Works Offline Push Notifications
10. #SearchLove @goutaste
Why are they popular?
Mobile sales increased by 18% YoY
43% increase in sessions/ user
100% increase in session duration 80% improvement in load time
30% higher Conversion Rate than
native app in Tier 3 cities
20% of PWA bookings are from
users who’d uninstalled native app
Homepage loads completely in .8
seconds
Customer acquisition cost is 10X less Shoppers spend 20% more time
than on previous mobile site
40% lower bounce rate than on
previous mobile site
https://www.pwastats.com/
11. #SearchLove @goutaste
The Web is Becoming Full of Web Apps
Photo: https://visualhunt.com/f/photo/3943667382/a851db711b/
16. #SearchLove @goutaste
Even Though Things Are Changing, JavaScript is Also
Still Hard for Search Engines*
*Search Engines means more than just Google
25. #SearchLove @goutaste
Old Linking Habits of JS-Heavy Applications
By default:
https://example.com/#/foo
For deprecated AJAX crawling scheme:
https://example.com/#!foo
(And ?_escaped_fragment=foo)
26. #SearchLove @goutaste
Death of the Hash & HashBang
By default:
https://example.com/#/foo
For deprecated AJAX crawling scheme:
https://example.com/#!foo
(And ?_escaped_fragment=foo)
https://example.com/foo
https://example.com/foo
27. #SearchLove @goutaste
Long Live the History API
Leverage HTML5
pushState()
Change URLs in the
address bar without
reloading the whole page
Great for Search Engines
& users (hello, sharing!)
https://css-tricks.com/using-the-html5-history-api/
35. #SearchLove @goutaste
Say a prayer to
the god of your
choice &
hope Google
figures out your
client-side
JavaScript?
36. #SearchLove @goutaste
But Uh… Good Luck With That
Googlebot may only be willing to wait 4-5 sec for your JS…
https://maxxeight.com/tests/js-timer/@maxxeight
37. #SearchLove @goutasteInline vs. External vs. Bundled makes a difference:
https://goralewicz.com/blog/javascript-seo-experiment/
@bart_goralewicz
Many JS Frameworks Still Struggle To Make It In
Time Without Additional Optimizations
42. #SearchLove @goutaste
Client Side vs. Server Side Rendering
https://www.youtube.com/watch?v=0wvZ7gakqV4
If you search for any competitive keyword terms, it’s always
going to be server rendered sites. And the reason is because
although Google does index client-side rendered HTML, it’s not
perfect yet and other search engines don’t do it as well.
So if you care about SEO, you still need to
have server-rendered content.
“
“
-- Jeff Whelpley
45. #SearchLove @goutaste
WTF Is “Isomorphic JavaScript”?
JavaScript code that can run on
both the client and the server.
Synonyms: Universal JavaScript, Shared JavaScript,
Portable Javascript
50. #SearchLove @goutaste
Ye Olde Days
(multi-page applications)
Circa 2011
(single-page applications)
Today
(Hybrid apps)
JavaScript Web – A History
https://www.slideshare.net/spikebrehm/2014-0313fluent/20-
Ye_olde_daysfatserver_thinclient
Bonus
Slide!
@spikebrehm
59. #SearchLove @goutaste
Improve Mobile Usability
Remove Flash
Configure
ViewPorts
Tt!
Use Legible
Font Size
Space Out Touch
Elements
Search Console Mobile Usability Report: support.google.com/webmasters/answer/6101188?hl=en
65. #SearchLove @goutaste
Do The Basics
Put Everything on a Diet:
– Smaller files
– Compress everything
– Less unnecessary files
– Less overall requests
– Don’t send code the
page doesn’t need
GIF: https://visualhunt.com/photo/44460/
68. #SearchLove @goutaste
Improving Page Speed with Images
Sprites File Size Responsive
Images.org
Image Server
Quality: 85%
Width: 300px
Quality: 70%
Width: 150px
Quality: 326 PPI
Width: 200px
69. #SearchLove @goutaste
1. First Paint 2. First Contentful Paint
“Is it happening?”
@addyosmani http://bit.ly/performance-kpis
70. #SearchLove @goutaste
Make it Happen Faster:
Speed Up Time to FP & FCP
Inline critical CSS &
JS
Remove all render-
blocking scripts
from the <head>
https://youtu.be/6Ljq-Jn-EgU
71. #SearchLove @goutaste
“Is it useful?” “Is it useable?”
3. First Meaningful
Paint
4. Time to Interactive
@addyosmani http://bit.ly/performance-kpis
72. #SearchLove @goutaste
One of the
Issues With
Server-Side
Rendering is
The Trade-
Off With
Time to
Interactive
Simulated Slow Networkhttps://youtu.be/6Ljq-Jn-EgU
73. #SearchLove @goutaste
One of the
Issues With
Server-Side
Rendering is
The Trade-
Off With
Time to
Interactive
Simulated Slow Networkhttps://youtu.be/6Ljq-Jn-EgU
75. #SearchLove @goutaste
Make it Useable Faster:
Minimize Time Between FMP & TTI
Ship less JS
Break up existing JS
into smaller chunks
(“Code Splitting”)
See Also: http://bit.ly/code-splitting-webpack
http://bit.ly/performance-kpis
76. #SearchLove @goutaste
Make it Useable Faster:
Minimize Time Between FMP & TTI
Ship less JS
Break up existing JS
into smaller chunks
(“Code Splitting”)
Follow the PRPL
(‘purple’) Pattern*
http://bit.ly/push-render-precache-lazyload
*”push” references H/2 push and requires http2
94. #SearchLove @goutaste
Lancôme USA
65% of their mobile web
users are on iOS
53% increase in session
length on iOS after
launching PWA
https://lancome-usa.com
109. #SearchLove @goutaste
1. First Paint 2. First Contentful Paint
“Is it happening?”
http://bit.ly/performance-kpis@addyosmani
110. #SearchLove @goutaste
“Is it useful?” “Is it useable?”
3. First Meaningful
Paint
4. Time to Interactive
http://bit.ly/performance-kpis@addyosmani
111. #SearchLove @goutaste
Measuring
The Metric
First Paint
First Contentful Paint
First Meaningful Paint
Time to Interactive
The Tool
Chrome DevTools 60+ Performance Observer Tab
Chrome DevTools 60+ Performance Observer Tab
Track loading of ‘Hero’ Elements (scripts)
github.com/GoogleChrome/tti-polyfill
https://youtu.be/6Ljq-Jn-EgU
115. #SearchLove @goutaste
INDEXING CHECKLIST
Make content crawlable:
Server-side or hybrid rendering
If you can’t:
Headless Chrome pre-rendering
Prerender.io or similar
Make sure your client-side JS renders in
4-5 seconds or less & test rigorously
Provide clean URLs
Leverage the History API
No hashes or hashbangs
Reconsider/ migrate ‘escaped
fragments’
Clarify everything with Canonicals
116. #SearchLove @goutaste
OPTIMIZATION CHECKLIST
Optimize for Mobile Friendly
Fonts/ tap targets
No intrusive interstitials
Optimize for CTR with Schema
Optimize for Speed KPIs (FP, FCP, FMP, TTI):
Minimize & compress code & images
Inline critical CSS & JS
Remove all render-blocking scripts from the <head>
Break up existing JS into smaller chunks (“Code Splitting”)
Follow the PRPL (‘purple’) Pattern
Optimize for Engagement & UX
HTTPS
Service Worker & App Manifest (progressive web app
features)
App shell caching
Offline Caching
Installable
Load as full screen
Push notifications
Polyfills for unsupported browsers
117. #SearchLove @goutaste
AUDITING CHECKLIST
Audit for Crawling & Indexing
Fetch & Render (Googlebot)
Fetch & Render As Any Bot
Compare Source & Outer HTML
Headless Chrome
Audit for App-iness
Checklist:
https://developers.google.com/web/progressive-web-
apps/checklist
Lighthouse
Cross-browser testing
BrowserStack.com, Browserling.com or BrowserShots.org to
ensure your PWA is cross browser compatible.
Audit for Speed
PageSpeed Tool
WebPage Test, Chrome Dev Tools
Actual User Data (Real User Metrics)
119. #SearchLove @goutaste
Thank You!
var me = {
name: “Emily Grossman”,
title: “Director of App Strategy”,
work: “MobileMoxie”,
twitter: “@goutaste”
};
var cat = {
name: “Daenerys Furborn of the House
Grossman, First of Her Name, the
Unfed, Queen of the Bengals, Catleesi
of the Great Scratching post, Breaker
of Treats and Mother of Cuddles”
};
120. #SearchLove @goutaste
Super-Smart, Helpful People
@ipullrank
@samccone@slightlylate
Technical SEO
PerformancePWAs
@_developit
Creator of Preact
@addyosmani
PWAs
@theLarkInn
Webpack
@bart_goralewicz
JS SEO
@maxxeight
Technical & JS SEO
@jonoalderson
Weird shit
@justinrbriggs
JS SEO
@dsottimano
Technical & JS SEO
@suzzicks
Mobile
Editor's Notes
From Website to Web-App:Index, Optimize & Audit SEO-Friendly Experiences for the New Mobile Web
http://www.liveanimalslist.com/mammals/duckbill.php
Google is one of the only Search Engines trying to deal with JS applications
https://giphy.com/gifs/xT0GqtpF1NWd9VbstO
Today I want to talk about 3 areas where we can help – INDEXING – making sure Google can crawl and properly index our web app content, OPTIMIZING – not just for rankings but for that app-like user experience, and AUDITING – being able to trouble shoot and measure areas for improvement.
Let’s start with crawling and indexing.
Although this may change in the future, Google’s ability to crawl and index our web content relies heavily on the principal that every unique piece of content has a unique URL.
Although this may change in the future, Google’s ability to crawl and index our web content relies heavily on the principal that every unique piece of content has a unique URL.
https://visualhunt.com/f/photo/5542857895/8f186be4b0/
To avoid this there are 2 things that need to be done.
Configuring $locationProvider
History API
Setting our base for relative links
Moving from these hash URLs to clean URLs is a PAIN IN THE BUTT because 301 redirects do not work with hashes. So if you can, do not introduce them in the first place. Otherwise JS redirects.
https://css-tricks.com/using-the-html5-history-api/
https://visualhunt.com/photo/104626/
http://diveintohtml5.info/history.html
The HTML5 history API is actually designed to ensure that URLs continue to be useful in script-heavy web applications.
Going back to first principles, what does a URL do? It identifies a unique resource. You can link to it directly; you can bookmark it; search engines can index it; you can copy and paste it and email it to someone else, who can click it and end up seeing the same resource you saw originally. These are all excellent qualities. URLs matter.
So we want unique resources to have unique URLs. But at the same time, browsers have always had a fundamental limitation: if you change the URL, even through script, it triggers a roundtrip to the remote web server and a full page refresh. This takes time and resources, and it seems especially wasteful when you are navigating to a page that is substantially similar to the current page. Everything on the new page gets downloaded, even the parts that are exactly the same as the current page. There is no way tell a browser to change the URL but only download half a page.
The HTML5 history API lets you do this. Instead of triggering a full page refresh, you can use script to, in essence, download half a page
FYI errors in pushState() can also cause 2 urls for the same content and duplicate content issues.
Before Google can index our web content, we need to make sure Google can crawl it. And this is where Rendering comes in.
https://visualhunt.com/f/photo/16055850189/460392d1e3/
https://visualhunt.com/f/photo/474542238/8097a7369b/
Javascript is a language that can manipulate the DOM without touching the source HTML.
We can kind of go back to “ye olde days!” as far as Google and other search engines are concerned
The downside to this is that we lose a lot of the benefits of implementing a JS-driven website in the first place!
https://visualhunt.com/f/photo/5406890987/63d3118a3c/
Really we need both
AKA:
Universal JavaScript
Portable JavaScript
Shared JavaScript
Serve a static version on the first request, by piping the output of the server-side to the page (based on the req path). Then let the client pick it up from there.
And really this makes sense when you think about a web app as something that both needs to have some static crawlable content and wants to be deeply engaging for users.
AKA:
Universal JavaScript
Portable JavaScript
Shared JavaScript
Performance
First paint can be faster (after framework rendering)
SEO
Makes crawling easier for Search Engines
Emphasis on “Search EngineS”
Maintainability
Performance
First paint can be faster (after framework rendering)
SEO
Makes crawling easier for Search Engines
Emphasis on “Search EngineS”
Maintainability
Performance
First paint can be faster (after framework rendering)
SEO
Makes crawling easier for Search Engines
Emphasis on “Search EngineS”
Maintainability
You choose, or maybe your framework chooses, which pieces of code get shared
But the important thing to remember – especially if you are working with a Framework – is that even though some frameworks support serverside rendering, pretty much none of them do it by default – so this is something a developer will have to set up. It’s a decision that ideally you will make and defend as you are setting up your development stack.
SaaS wrapper for PhantomJS
Prerender IO was built on headless library Phantom JS to render the page and take an “html snapshot” that can be be used for SEO
SaaS wrapper for PhantomJS
Prerender IO was built on headless library Phantom JS to render the page and take an “html snapshot” that can be be used for SEO
Testing is probably the most important part
I’m not going to go into how to check and see which pages on a website are not getting indexed – let’s assume you all know how to do that or how to google it
– but what you might not know how to do is troubleshoot for WHY certain pages are not getting indexed – or more frequently, why they are getting indexed improperly
https://twitter.com/_developit/status/862686014447509504
https://www.google.com/webmasters/tools/googlebot-fetch