Many people have an interest in building websites that take advantage of AJAX principles, while still being accessible to search engines. This is an important issue that I've written about before in a (now obsolete) post from 2010. The tactic I shared then has been superseded by new technologies, so it's time to write the update.
This topic is still relevant, because of a particular dilemma that SEOs still face:
-
websites that use AJAX to load content into the page can be much quicker and provide a better user experience
-
BUT: these websites can be difficult (or impossible) for Google to crawl, and using AJAX can damage the site's SEO.
The solution I had previously recommended ends up with the #! (hashbang) symbols littering URLs, and has generally been implemented quite poorly by many sites. When I presented on this topic at Distilled's SearchLove conferences in Boston last year, I specifically called out Twitter's implementation because it 'f/#!/ng sucks'. Since I made that slide, it's actually got worse.
Why talk about this now?
In general, I'm surprised that we don't see this approach being used more often. Creating fast, user-friendly websites that are also totally accessible by search engines is a good goal to have, right?
What is the technology?
So - drumroll please - what is the new technology that's going to make our AJAX lives easier? It's a happy little Javascript function that's part of 'HTML5 History API' called window.history.pushState()
pushState() basically does one thing: it changes the path of the URL that appears in the user's address bar. Until now, that's not been possible.
Before we go further, it's worth reiterating that this function doesn't really do anything else - no extra call is made to the server, and the new page is not requested. Plus - of course - this isn't available in every web browser, and only modern standards-loving browsers (with Javascript enabled) will be able to make use of it.
In fact, do you want a quick demo? Most SEOmoz visitors are using a modern browser, so this should work for you. Watch the page URL and try clicking ON THIS TEXT. Did you see the address change? The new page URL isn't a real location, but - so far as you're concerned - that's now the page you're looking at.
SEOmoz readers are smart people; I expect that you're realizing various ways that this can be valuable, but here's why this little function gets me excited:
-
you can have the speed benefits of using AJAX to load page content (since for many websites, only a fraction of the code delivered is actually content; most is just design & templating)
-
since the page URL can accurately reflect the 'real' location of the page, you have no problem with people copy/pasting the URL from the address bar and linking to / sharing it (linking to a page that uses #fragment for the page location won't pass link-juice to the right page/content)
-
with the #!s out of the way, you don't need to worry about special 'escaped URLs' for the search engines to visit
-
you can rest easy, knowing that you are contributing good quality URLs (as discussed in the post montioned earlier) to the web.
The Examples
I launched a pushState demo / example page to show how all this performs in practice.
Click the image above to visit the demo site in all its glory.
If you click between the cities in the top navigation, you'll be able to see that only the main content is being loaded in with each click; the page navigation.
(This can be confirmed by playing the Youtube video on the page; notice that it doesn't stop playing as you load in new content.)
If you want to see a bunch of examples of this 'in the wild', you can take a look at almost any blogspot.com-hosted-blog with one of their new 'dynamic views' in place, just add '/view/sidebar' to the end of the URL.
If you click posts in the left hand column on that second link, you'll see the content get loaded in with very impressive speed; the URL is then updated using pushState() - no page reload took place, but your browser still reflects the appropriate URL for each piece of content.
The Techie Bit
If you like the sound of all this, but you start to feel out of your depth when it comes to tech implementation, then feel free to share this with your developers or most tech-oriented friends. (References are linked at the end of this post.)
The important function we're utilizing takes three parameters:
window.history.pushState(data, title, url)
There's no value in worrying about the first two parameters; you can safely set these to null. In the brief example I gave at the top of this post, the function simply looked like this:
window.history.pushState('','','test/url/that-does-not-really-exist')
Our workflow for implementing this looks like the following:
-
Before doing anything else, make sure your site works without JS; Google will need to be able to follow your links and read content
-
You'll also have to create server-side processes to serve just the 'content' for particular pages, rather than the fully rendered HTML page. This will depend a great deal on your server, your back-end set up; you can ask in the comments below if you have questions about this bit.
-
Instruct Javascript to intercept the clicks on any relevant internal links (navigation elements, etc.) I'm a big jQuery fan, so I rely on the click() function for this
-
Your Javascript will look at the attributes of the link that was clicked on (probably the href) and use whatever JS/AJAX you want to load the appropriate content into the page
-
Finally, get all the SEO benefits by using the pushState() function update the URL to match the content's 'real' location
By having your internal links work 'as normal' and then adding this AJAX/HTML5 implementation on-top, you are taking advantage of the benefits of '
progressive enhancement': users with up-to-date browsers get the full, fast and spiffy experience, but the site is still accessible for less capable browsers and (critically in this case) for the search engines.
If you want some code to implement this, you can take a look at the head section of the demo that I shared above - that contains all of the Javascript necessary for doing this.
Basic code for getting this done looks like this:
// We're using jQuery functions to make our lives loads easier
$('nav a').click(function(e) {
url = $(this).attr("href");
//This function would get content from the server and insert it into the id="content" element
$.getJSON("content.php", {contentid : url},function (data) {
$("#content").html(data);
});
//This is where we update the address bar with the 'url' parameter
window.history.pushState('object', 'New Title', url);
//This stops the browser from actually following the link
e.preventDefault();
}
Important Caveat
Although the code above works as a proof of concept, there are some additional things to do, in order to make this work as smoothly as my demo.
In particular, you'll probably want the 'back' button on the user's browser to work, which this code snippet won't allow. (The URL will change, but the content from those historical pages still needs to be loaded in.) To enable this, you'll need the popState() function; this detects a URL change, allowing you to fire whatever function you have for grabbing page content and loading it in.
Resources and Further Reading:
There are plenty of resources that cover the HTML5 History API pretty thoroughly, so I'll defer to them in letting you read about the details at your leisure. I'd suggest taking a look at the following
Rob Ousbey for the win! This couldn't be more timely for me. I have a meeting in the AM on making an AJAX site crawlable and you just armed me with an atomic bomb. Hell yes!
-Mike
Briliant post & very useful.
There's a nice little warning tucked in here to be extra careful when doing things like this. eg. Try clicking 'ON THIS TEXT' (above in the post, in bright orange) multiple times to see.
Great advice, Dan... Thanks!
Good catch Dan!
For anyone wanting to avoid that issue: I should have included the leading slash in there (eg: '/test/url') instead of a relative link ('test/url').
Is the URL change limited to the same domain you are already on? Otherwise I'm concerned about phishers using this technique to make bestbuyy.com look like bestbuy.com, etc.
Great question. Yes - this security is enabled in the browser: you can only change the path. The subdomain can't be changed, since (as you point out) it would allow phishing all too easily. That's not made particularly explicit in the developer docs.
could a phisher buy a .co domain and push an m onto the end?
making bestbuy.co become bestbuy.com for example
No. Because bestbuy.co and bestbuy.com are 2 different domains. You can only change the path and not the domain ( I believe neither the port as it would become potentially a new domain ).
Hello. I'm new and I have a question.
Some of you could give an example of how the file content.php
Thank you.
This seems to be a great step forward. I am only concerned about the fact that only modern browsers support that. Even in IE9 (!!!) it is not working. I guess most of us SEO's do have modern browsers, but most of the customers don't and they expect that their website will work for all of their customers. So I am all the time ambivalent with such technical steps forward. But nevertheless - great blog post!
Rob, great, great post. Thanks for sharing here buddy. Hoping to be in Seattle soon - and I'd feel honoured to buy you lunch to talk technical. Love reading your stuff.
> I'd feel honoured to buy you lunch
Thumb up.
Hi Rob,
Thanks for the very informative post, but i have a few questions, (again please note that i am not a programmer so there is a possibility that you might my questions extremely stupid) -
- Sajeet
Hi,
I also agree with Mr. Sajeet...
One more thing, I have clicks so many times on and it shows to me this url - https://www.seomoz.org/blog/test/url/test/url/test/url/test/url/test/url/test/url/test/url/test/url/test/url/test/url/test/url/test/url/test/url/test/url/that-does-not-really-exist
is this url will not be created on google? If every click it will make a new url than we will created so many 404 pages as well....
Please clarify to me....
Thanks.....
Good questions.
Basically, this is a relatively blunt tool - it's up to people to make sure they implement it properly. This should be considered a new way of navigating between pages. If there is dupe content on those pages (as on my demo site) then that's something of a seperate issue to pushState().
In terms of the proof-of-concept 'on this text' link in the post, remember that it changes the URL to a page that does not exist. If someone actually visits that URL, it will just 404; Google won't find any content there.
Re: data drawing APIs: I can't think of an appropriate use case here. If that content is just being regularly loaded into the page, there might not be a necessity for URL changes
This will work regardless of what language the back-end of the site is written in. If you do some research into 'HTML5' you'll see that it's often not difficult to make your pages into HTML5 - it might be as simple as changing the doctype. You can then use any of the HTML features that the user's browser supports.
This is awesome stuff Rob. All the benefits of slick Flash websites interface and all the benefits of SEO optimized pages. I think this will have a big impact on site design and usability in the coming years. You are now my favorite ginger for the week.
I wish I could give this more thumbs up - this is the kind of material that actually pushes our industry forward.
I am dying to try this out now, thanks for ruining my week ;)
As Mike wrote before: thanks and very timely post! Actually, in fact, I am dealing with a couple of clients whose old slow sites are going to be redesigned, hence this technique will be surely considerated. Thanks again Rob.
I'm not 100% sold on this post. I'm more of a developer than an SEO guy but I do understand a lot of the SEO realm.
I do think we should start implementing this for UX reasons, though I doubt any browsers 'back' button will work properly.
Basically the proper implementation of this is to allow people with JavaScript enabled to use AJAX for better user experience. If you have a shopping cart and you allow users to funnel the results via AJAX under normal circumstances the Address Bar will not change. So if you funnel the results down to a page and you want to show a friend the page you see, they'll end up seeing the non-funneled results. This gives you the ability to link to the AJAX created content.
BUT and it is a huge but, if you do not build your website to gracefully degrade when JavaScript is turned off by creating hard links so user can navigate to these pages without ajax it won't work at all.
So if you don't build your website so it works 100% for users with or without JavaScript enabled, all you are really doing is manipulating the text in the address bar for JavaScript enabled users.
This is an important point.
In fact, people have generally stopped using the term 'graceful degredation' now, since this implies having to have a 'backup solution' for less capable browsers.
Instead, it's better to think in terms of 'progressive enhancement'. That is: get it working in all browsers (including Internet Explorer) and get it working for search engines, and THEN add these features on top, improving the experience for people who have browsers that are capable.
This guarentees that your site will be accessible to everyone, and there won't be any need to worry about how it degrades.
This is great! Thanks Rob, already trying to mastermind some uses for this.
I agree with Mike on this one. ;) Rob Ousbey for the Win!
Forwarding this article to the IT, I have a feeeling we will use it. Thanks for sharing.
Gr., Istvan
Very Interesting and a complete power pack information!.. First of All thank you for that wonderful post as now I can back my idea of using Ajax on the website.
But, I am Pretty much on the same question as “algogmbh_petra” is that... may be smart SEOs use the modern browsers but what about the user who I am sure does not use the modern browsers...
I've used this out in the wild and I've got to say that this isn't the silver bullet for SEO on Ajax websites, although it's close.
Google's crawler runs some Javascript (check out the second answer to this SO question). So your javascript that catches a click event from a hyperlink and dynamically loads the content onto the current page and disables the hyperlink's action WILL screw up the google bot's crawling of your website.
Currently I have a site that is being indexed by google that is using the pushState() html5 functionality to dynamically load all hyperlinked content, and google is not crawling past the front page.
You either have to go back to using ugly hashbangs, or use the pushState() functionality with a sitemap.xml file and hope that works. I'm going to test out the sitemap.xml file with the pushState() functionality to see if it works.
hello rob. very good job. but I need help. could put a download of the example? . I'm new to programming and I fail to understand the links to other pages.
<li> <a href="/seattle"> Seattle </ a> </ li>
<li> <a href="/new-york"> New York </ a> </ li>
<li> <a href="/london"> London </ a> </ li>
????
I need the file content.php?? please help and thanks in advance.
Hi Bob Great article :)
i need your advise for my website. i have a fully ajax based website. like i think google can crawl only index page. so i am thinking of using this technique https://developers.google.com/webmasters/ajax-crawling/ . can you tell me what i should do? i am new to html5 so confuse what to do.
Thanks in advance,
Umair :)
hi
I am using Advance Ajax in my website and only # tag is used but not the #!.
So should i use #! in order to make pages crawlable ???or it is fine with # only ?
and some pages does not change URL even after the click of user,as they run ajax but URL remains the same.
So,should i modify them and URL must be changed on every click ??
Please reply ASAP
This looks exactly like what I'm looking for, my only problem is knowing where to start with implementation.
I have this site (WIP, not yet live): https://keithneilson.co.uk/experimental/products/ which loads product information from a separate html (/Data/prod-data.html) file when that product's listing on the main page is clicked. The information loaded is displayed in a modal element. Currently the listings don't have an associated element. My questions are as follows:
1. Do I need to add an element to each of my product listings?
2. Does each product listing require a unique state url?
3. If .pushState() changes the url in the address bar will this url link to the exact state of the page if included on another page?
4. Image links in prod-data.html only work when inserted into the page that the ajax request originated from, is this an issue?
5. I want to make the information in prod-data.html indexable but don't want that file linked to in search results, is this doable?
I'm sure I'll have more questions as work progresses and I get my head around this ajax lark :)
Hi.Thanks for the great article.I have an issue in implementing the code though.As far as I am concerned, when I go to directly to www.myurl/dashboard/varpage the content is loaded via php so I do not need the content loading anymore.Is there a way to replace the window.onpopstate = function(event) to something that would only update my content div on back/fwd NOT on full page load ?It would not be a problem if I wouldn't want to check if my php content is loaded correctly and for performance sake , loading the content twice is something that is not making me feel very comfortable.
Thanks for this tutorial!have a question about if content page is index.php?id=_ , how to avoid pushstate twice/ different url and make popstate works fine?
https://stackoverflow.com/questions/14025328/making-ajax-lightbox-with-unique-url
Thanks for any help!!
hello
first of all I would like to thank you for your great work... its really cool but what really I don't understand is how you make your ajax returned data to appear in your source code like if i view the page source code i see each value in the right place ... !! and when i try to use your function and test it it won't work with me at shows the ajax returned data on my page and also i can see it in firebug DOM but when i view the source code i could not find any of the returned data...
please explain to me how you made that ..
thanks
Hi Mohammed,
The important lines in the JS are these:
$.each(json, function(key, value){ $(key).html(value);});
If you look at the returned JSON, you'll see that the key names are the descriptors for HTML elements, such as 'title' or 'article #articletext'. The Javascript above looks for each of these HTML element and then fills them with the value of the relevant item.
hello RobOusbey
yes I understand this function and it really work with me but what i mean is when i view my page sourse i see the tags are empty even if its text appeared in the right place in the DOM .. I mean .. by another way ...
when you create ajax request (ajax / get / post / live / getJSON ... / etc) the source code for the returned data dose not appear when i ask the browser to show the source code but in your case it appears in the both ways .. the source code and the real page ... as if you use include function not ajax request...
like this
<div id="results"></div>
but in fact there is a returned data in the page in this div
If you use 'View Page Source', you'll only see the original page source, not any data that was added via Javascript.
Instead, you should use Firebug (for Firefox) or the Webkit Inspector (for Chrome) by right clicking an element and selecting 'Inspect Element'.
Today I realized that we have this very issue with our application which we need to fix. Our app is written in ASP.net with a lot of GridViews displaying records. Most of our content that need to be crawled by search engines are in these tables with paging as well.
I don't see how this can help us. Do you mind describing briefly how this could work for our situation. I need to be specific when I talk to the developers if I wanted done right the first time.
Thanks
Hi Rob,This is a great tutorial! I do have a question though...
I am working on a site that uses modal windows that are called via AJAX from absolute urls. This has created a few problems, the content in the modal is great content, but the absolute url is getting indexed and appearing in the SERPs. What you arrive at is what is supposed to be presented in a modal window, but it is presented full-screen with no nav no branding no nothing.
Can this pushState() technique overcome this? By say... having the parent page with the modal popped open having it's own unique url? Kind of like Google's AJAX server snapshot you referenced in one of the comments here but w/o all the messiness of that approach.
Thank you,Jim
Interesting issue. I guess one option would be to:- change the URL using PushState when the modal opens- if that URL is directly requested, then serve up the page with the modal already visible. (Making sure not to serve up other duplicate content.)
However, if you're using an iframe to pull in content, this doesn't avoid the risk that the 'hidden' URL will still get indexed. In this case, you can now put a rel=canonical from that page over to the 'modal visible' URL; since the content is present on the destination URL this is totally legitimate.
Here's an alternative solution:- have a proper page for that great content, with navigation/branding/etc.- the links on the main page should link to the great content page when JS is off, and open up the modal when JS is on- when displaying the modal, use AJAX to fetch the 'pure content ' (no branding/navigation) and display it, but make sure the URL it's requesting from is blocked by robots.txt - so Google can't accidentally index that.
I hope I didn't just complicate matters more. Did that make sense?Rob
I think that another solution to that is to make your modal window bookmarkable. Say that you listen to URL Hash Change by Javascript.
You have a main page at: www.mysite.com/page_with_modal_window
And then, when the user triggers the opening of the modal window, you obtain something like www.mysite.com/page_with_modal_window#great_content_modal
As such, when I'll paste: www.mysite.com/page_with_modal_window#great_content_modal, you will open the page, and after the page has been loaded, you trigger the Hash Change and re-open the modal window. Making your modal window bookmarkable.
I believe that Google will see this as a page, or then you will have to use the
www.mysite.com/page_with_modal_window#great_content_modal for browser
and www.mysite.com/page_with_modal_window#!great_content_modal for google bots ( with a ! as uglyfying marker )
Hope that helps.
Thanks, Rob.
I'm a web designer with some programming skills, so I think I've got most of this except...
"You'll also have to create server-side processes to serve just the 'content' for particular pages, rather than the fully rendered HTML page. This will depend a great deal on your server, your back-end set up; you can ask in the comments below if you have questions about this bit."
Can you talk a little bit about that point? Thanks in advance.
Hi Rob,
Google indexed your demo web site (https://html5.gingerhost.com/ ) successfully with ajax contents as it is seen (https://www.google.com.sa/search?sourceid=chrome-p... ) .
My questions are :
Did you provide a snapshot service to googlebot for indexing content?
and
what is your opinion for the following question? stackoverflow.com/questions/39614196/ajax-c...
Thanks.
I know this is a year old, but did anyone get the content.php file?
Nice, thanks! Sorry Im new to this but I was recommended by an SEO consultant to remove all my ajax calls for my search results and instead statically show them all on the page so that Google can crawl the content - with pushstate, I am guessing that is not necessary?Thanks
Great post Rob, however this isn't really new. As far as I know we can already put full links in and add attributes i.e. load-page="xyz.php" or page-id="3" and have jquery capture the click, prevent default, and pull action from the attribute. This also doesn't really solve crawling generated JS (unless of course it's a rendered page), which I was hoping for. I've developed a embeddable ecommerce platform that users can use on their site, however I'm still trying to determine the best way to crawl data. It almost makes more sense to have those links point back to the original server and render a dummy page. This new pushstate function is sweet though, definitely going to use that!
Can I see an example of the content.php file?
Greetings Rob!
Surely you have written an excelent article. Although I noticed that there is a ordinary question between most people here.
I have the same doubt, as the colleagues above.
After all, where could I find this supposed file "content.php"?
We need it to understand the process, and to do our own pages, using ajax with your new implemetation.
Thanks for your atention!
I am not able to get this work… it's driving me crazy. It is not fetching the content from my content.php… and when i refresh the page at a city state it says 404…
Does anyone have idea how content.php should looks like ?
Awesome resource. Does anyone have a compatibility report?
Very nice post! Does it work on a site that its content is made through PHP variables?
I have an index.php with a line of code that loads content based on a GET type variable. I tried enclosing the PHP line <?php include ... ?> with the <div id="loading"> but even though the URL is being changed, the content is not being loaded.
Any thoughts will be really appreciated.
Thanks in advance!
Hey Rob,
Great article! I think this is want I have been looking for. I just had few questions. I have designed a single page website using Knockout js, the links on my page point to the different sections on the same page (for example, aboutMe section, abc section, pqr section). When I click on the links, I'm taken to that section with url#aboutMe. Can you tell me how can I use pushState in my website. I'm not using server-side renderer; I'm getting JSON data by making REST API calls.
Thank you.
I'm a bit late to the party I guess. My site has been live for 1 month now and none of the urls with # are being indexed. It is published through WIX. Hopefully it will get indexed eventually.
Hi Rob, I understood the URL changing, but I didn't understand how Google is going to read the content loaded by AJAX and consider it as a page. The content loaded at $.getJSON("content.php", {contentid : url},function (data) { $("#content").html(data); }); will have to be loaded also in the first param of pushState function? Thanks, João.
This is awesome bt id realy like to see how the content.php looks like so as to get the framework
I wonder, how you managed to implement the contents of the requested source code of index page?
Yeah, I noticed this detail when I sailed on her example, and I'm looking for a way but could not reproduce this feature in my code. Have you used any new object element (for html5) or any specific method?
My code is in pure javascript with a simple ajax call using pushState and onpopState that performs the ajax request quietly, but does not insert the contents of the requested page in the body of the standard page.
Because I would like to improve the SEO of my site and this feature would be a ecensial tool.
Thank you in advance for attention.
One question I have after reading the Google documentation: will Google start uglifying URLs of every page that doesn't have the <meta name="fragment" content="!"> in it?
Is this still a legit solution?
Hello!
I'm new too.
I want to download the full demo page, it's possible?
Hi!
I'm trying to develop an Ajax-driven website with SEO capabilities, following your great tutorial.
I added the pushState() method to update URLs and, depending on which of those, I call different JSON content by Ajax.
Unfortunately, it seems Google's getting hard to index my Ajax contents.
Could the reason why be that pushState() URLs don't exist?
I mean the "folders" I dynamically update but don't exist in my server filesystem...
You wrote:
"By having your internal links work 'as normal' and then adding this AJAX/HTML5 implementation on-top, you are taking advantage of the benefits of 'progressive enhancement': users with up-to-date browsers get the full, fast and spiffy experience, but the site is still accessible for less capable browsers and (critically in this case) for the search engines"
Were you talking about creating real "folders" (corresponding to the pushState() URLs) in the filesystem?
Thanks so much, this thing is critical for me.
asnothingelse
Rob- This wouldn't seem to help with web sites developed in AngularJS or similar technologies. Does anyone disagree? We can separate this from the discussion of why one would or would not use these technologies.
It's perfect, but could you add content.php file for all of us to make example working?
I would be appreciate for example demo files, Please! :)
The basic function of window.history.pushState() is it changes the path of the URL that appears in the user's address bar and I'm very hapy that I've learned this from you.
It would really help to see a full theme taking advantage of this setup. Have you given any consideration to creating a modified WordPress default theme that takes into account all of the best practices you are mentioning in this article?
Will Google see these "page changes" as "page views" though? And thus count them towards any "pages per session" metrics?
Are you thinking from a Google Analytics perspective? This won't trigger a new page view, but it would be pretty trivial to include a call to a GA event in your Javascript and make sure that the page view is recorded.
Good idea!
Hi Rob,
Yes, GA, advert calls and more specifically how Google will see the page changes.
GA and advert calls can easily be driven from page code triggers. It's the Google page views that I'm concerned about.
What affect will this have on page views per visitor - a possible SEO metric?
Awesome post! Thanks. Already implement it and works fine for me.
Such a great article , I just instructed our guys to read up on HTML5 CSS3 and AJAX to rebuild our site for speed!
Brilliant! I am dying to try this on my new blog (see if I can get WP working with it)! Thanks for sharing and setting up the tast-case page :)
This already made my day; at it isn't even noon Monday yet!
Very cool. Will definitely need to look into creating AJAX websites immediately. Love the demo, color me impressed!
Very useful post. Thank you very much. Now all I have to do is convince my superiors of clearing the budget for the neccessary changes on our sites. This will be the hard part.
I've been using this on some of our internal websites as a kind of "test" for the real world (which we can't currently release because of older browser commitments) and it is fantastic! I believe GitHub have been using it for a while too, which is where I got the idea from. It's incredibly easy to implement and just seems to work.
I also use it for tabbed navigation where content is shown and hidden upon a tab click. Without JavaScript the url opens the correct tab and with JavaScript the URL changes but all content is just shown and hidden :-)
intresting post... i might send this to my developer... as he might be the right person who can explain me it with the words i understand easily ;)... intresting post :)
thankx
I tried the demo (on Firefox), thought the browser crashed at first to be honest.
Took ages to fully load ...
When I had almost gave up, worked then :P
Rob,
Honestly most of this went over my head :)
But it's a great resource to send the developers to when working on a new project which involves Ajax.
I'd also like to know if there is some fall back mechanism/ graceful degradation when implementing for users whose browsers do not support this.
Thanks for following up your old post.
Cheers.
Yes, this does work well in browesers that aren't able to cope with the HTML5 functions: the links will behave as normal, and just take the user to the target page, with a page reload. You can test the demo above - https://html5.gingerhost.com - in InternetExplorer to confirm this.
Hi, the fallback is great! I was just wondering though, how have you implemented the fallback? Have you used PHP to load the content and how have you made that work with '/london' rather than 'index.php?page=london'. Did you use htaccess?
Thanks.
Hi Rob, thanks for this awesome post. First I clicked the "On This Text" Demo and after that the Push State demo / example and then hit the back button I got a SEOmoz 404 page but you clarified this in your article.
Very interesting article, although only users with modern browsers (eg, current Google Chrome) can benefit from this technique.One should keep in mind this technique or implement this in part to new websites already. Especially with the use of an MVC pattern (for example, with the Zend Framework) this is quite easy to implement. Contents of a view can be delivered with activated or deactivated parts of the template (header, sidebar, etc.), completly other templates and much more depending on the request (headers).
Useful article. I think is going to stop all debates between Web Designer/Developers and SEO Consultants! A great cake to get every web department to agree! Thanks a lot...
Thanks Rob. Exciting. I am in the middle of trying to determine how well Google will parse and record my content on hidden (linked to, nothing dark) pages using ajax for use on website with a ton of information. Great a solution is in the works.
Interesting note: If you click on the "On This Text" link to the pushed URL, then click on the link to the blogspot/view/sidebar/ it will open in the same window. When you hit "back" it goes to the "Post Not Found" page, which looks too plain to be the official Moz custom 404, after seconds that page automatically redirects to the seomoz.com/blog page. I do not see errors like this on Blogspot.
Thanks for the post!
The only way to do this that makes sense to me is:
I've been thinking about making a service which does 2) because nobody else seems to. If anyone would use it, that is?
Your point 2) is quite interesting. Would avoid all the hassle to people that don't really get how to create an HTML snapshot and/or how to serve it.
But... I believe it would tough to gain trust that you wouldn't use your service to give to Google some other content. Have you thought about this?
Really excited to give this a try. Could never get the #! tricks to work right. So happy I might be able to get more pages/content indexed. Good looking out!!
That's a great find, Damm I like this:)
This article was also worth reading: https://danwebb.net/2011/5/28/it-is-about-the-hashbangs
I tested your test site in Chrome, Firefox, Safari and it worked flawlessly!
Only on IE8-9 I couldn't get the video going while changing pages but getting a page refresh is still better than those f/#!/ng hashbangs.
I don't understand people complaining it's not usable, because it is!
As others have stated, it looks as though it will be a few years before we can use this in earnest (Stupid IE9).
https://caniuse.com/#search=pushState
I love it :-)
may I suggest an improvement... Use HiJaxing to load the content (making it work in older IE browsers) but layer this on top (so you can still link to the underlying URL). What do you think?
Rob,
Demo at https://html5.gingerhost.com/ is really good and I'd like to use similar approach in application I'm going to develop soon but there's still something I don't get. When home page is opened and you click navigation buttons then you do pushState, GET content.php containing selector -> content pairs and 'render' the page. That's clear to me. But what happens on server side when https://html5.gingerhost.com/london is being opened directly from address bar? I see that you don't dynamically load content after page is loaded (like in hashbang apps) but somehow fully rendered document is being returned from server. Do you make similar templating like on client side or these documents are simply static HTMLs? If it happens dynamically then isn't that a solution for SEO friendly single page apps?:)
Thanks. Yes, the pages are served up in a static fashion, if you request the URL directly.
In this case, I used PHP to put the relevant info into the page template - but it doesn't matter a bit how you do this. If you had flat HTML files stored on your server, that would work fine.
pushState can be used to enhance the existing experience - so build the site to work normally first, then use this technique to make it better.
Exellent tutorial! I am currently design a site for a friends photography, and amidst the excitement of using ajax for a more fluid site, i decided to ignore back button functionality in the name of UI development. With pushstate i can have both!
One thing is bugging me though. When i copy/paste your 'generated' URL's, it directs me to the site with the corresponding content loaded in the main div. However, on my site i get 404 errors when i try to copy/paste the URL.
It's worth noting that i haven't used JSON, mainly because this is my first attempt at an AJAX site and i was more concerned with the css animations of the menu. So, am i still able to add this functionality to my site, or should i consider restarting the content loading with JSON (in which case, will my css animations still work?)
Thanks in advance,
Rob
Nevermind, i figured it out with the .htaccess file. Might be worth mentioning that somewhere for those using apache servers :)
Great stuff. One of my clients is using AJAX, thanks for sharing.
well GREAT JOB you have done here. It is what Ive been looking for.
If this works only in some browsers (as someone pointed out above, it does even work in IE9), how does Facebook accomplish this? When you click on a photo, it is loaded in a modal window, and the URL changes.
Really good post! I have been wanting something like this for a long time!
This alerted me to a potentially major issue on a site: trekity DOT com.
The whole homepage is AJAX, and it doesn't seem the spiders can crawl it at all. Would your proposed solution allow spiders to crawl this site? If so, how?
Thanks so much - this was a really great read!
Yes, that site clearly will have an issue when it comes to asynchronous loading of the content - but just trying to use pushState isn't the answer.
I'd have some 'standard' content get loaded in with the HTML, and then let the existing AJAX overwrite it as necessary. Then the search engines will at least be able to see something similar to users.
There could be an opportunity to change the URL with pushState() as people select from the navigation/filter buttons on the left though; but I wouldn't make that the priority.
Brilliant! Perfect for the presentation i'm gonna make in two weeks! THX!
Great post Rob I had been wondering how to do that for a while.
Thanks for this tip! It's great for:
- User experience
- crawlability for spiders
- but what about user behaviour metrics that Google use in his algorithm ?
Is google able to catch user behavior on this pages?
wow, this is really cool.
I personally don't use much ajax, but my developers heavily rely on it.
One thing I'd be interested in is if flash (swf object) could control this PushState() function. That would leave to much better flash + alternative content for SEO. Today I have to live with ugly url if I want to have flash (.com/#/?link=services), but my alternative content is services.html. Tried .htaccess - no luck :(
Anyway, great post. If anybody knows how to resolve this in flash, please share.
Best,
This is an awesome find Rob.
I believe that this implementation will be a very powerful tool in the hands of technical SEOs.
Thanks for sharing!
I am sorry but i doubt if this is really a solution? Because it will just change the content in #content div. It will not pull meta title, keywords and description for that page. How will google crawl this important information of each page then? Please advice. Awaiting your reply.
Because each page has it's own url that is visible by itself for example https://html5.gingerhost.com/seattle Google should have no issue indexing the page.
This is dumb, and it has nothing to do with getting rid of hashbangs for ajax - as far as I can tell from this article. Any good developer knows to bind events to elements by ID or CLASS no need for a hashbang. I don't know what you are using hashbang for, but google is pretty smart and can crawl ajax nowadays so I don't know what you mean by hurting SEO
They are testing crawling AJAX, but cannot master it yet. I have recently done a few content checks, to see if it is indexed and the jQuery and AJAX content was not indexed.
So I don't know, but meaning that it can crawl does not per-se indicate that it will also be indexed. The difference can be a few days, weeks, months or even a year. Would you like to say to your client that it is almost sure that the content won't get indexed at the moment, but possibly can be in the future? I'm sure that your client won't be too satisfied with it.
Well I don't have clients for SEO I mainly just do this for myself, but I get your point.
I have had ajax content on a site before and it was crawled by google (jquery), didn't seem to take too long.
Hi Corey,
The proposal to use the Hashbang for AJAX crawling came from Google themselves. Here are a few references:
https://googlewebmastercentral.blogspot.com/2009/10/proposal-for-making-ajax-crawlable.html
https://developers.google.com/webmasters/ajax-crawling/
Thanks Rob I was unaware.