Google console fetch & render does display AJAX fetched content - ajax

I have published a reactjs website that relies on AJAX requests (POST requests on a graphQL API if that's relevant) to display data.
Using google console fetch & render service, I can see that only my components that do not have to call any API are rendered. Any AJAX based component is not rendered at all.
Google fetch & render does show me 2 rendering pictures of my website (google vs visitor), but both are missing AJAX content.
Is server rendering mandatory in this case ?
I do not have a robots.txt file.
I'm doing something like:
import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { observable, runInAction } from 'mobx';
import axios from 'axios';
import ContributorList from '~/components/global/ContributorList';
import type { User } from '~/types';
import CSSModules from 'react-css-modules';
import styles from './style.less';
#observer
#CSSModules(styles)
export default class Footer extends Component {
#observable contributors: Array<User> = [];
async loadContributors () {
const { data: {
data: data
} } = await axios.post('/', {
query: `
{
users {
id,
name,
slug,
avatar {
secure_url
}
}
}
`
});
runInAction( () => {
this.contributors = data.users;
});
}
componentDidMount () {
this.loadContributors();
}
render () {
return (
<div styleName='contributors'>
{ 'Static content' }
<ContributorList
contributors={ this.contributors }
/>
</div>
);
}
};
In my browser, I can see everything fine ('Static content' + contributors that rare fetched asynchronously). But with google fetch and render, I see 2 screenshots with only 'Static content' displayed.
As a result, my dynamic content does not appear in google search results.

Now all the people are talking about progressive web apps (PWA) which rely on Ajax and rendering the content of the website using client side techniques.
But these techniques are not SEO friendly at all, since Google can't index the classic Ajax request and most of the modern requests.
Since you are using ReactJs, and you want Google to index your website you have to use server side rendering.
This will slow down your website and at the same time Google can crawl and index all your pages, also the user can view it on any device, even the old devices.
When you want to build a PWA or modern web app in general, you have to go back to the basics, for an old technique called graceful degration, which mean if you disabled the JS from your browser still you can see the content and all the functions on your website are work.
This is the same way Google crawl and index your website.
There are many recommendations from Google regarding crawling Ajax content:
Use clean URL structure and avoid using JS links(javascript:void(0);)
Load all the using server side rendering
Make sure that your website is working on all devices(responsive)
Submit XML sitemap
Use canonical links in if you have more than one URL structure (which is not recommended)
We are working on a new project similar to yours, built using reactjs and it will be one of the first PWAs in the world that Google can crawl it like any other website by doing the above points.
Also Google have published an article on their webmaster blog talking about the PWA and any modern web app like yours.
For more details check this link
https://webmasters.googleblog.com/2016/11/building-indexable-progressive-web-apps.html
Regarding the robots.txt file, its recommended to add robots for any website even if you don't have pages to block, but you may want to block the ajax requests and other annoying crawlers.

Related

I'm trying to display Tableau workbooks on my webpage, but the result is blank page

My web is Laravel-VueJs App, I managed to sign in to Tableau server automatically in the background, (but without getting Auth tickets (I'm not sure if I need tickets for Javascript API yet), I'm trying to show my workbooks on my web page but getting blank page without any error, however this is my code
first added Javascript API in my app.blade.php
<script type="text/javascript" src="https://my-server-url/javascripts/api/tableau-2.8.0.min.js"></script>
and this is the Vue component where I need to show workbooks
<template>
<div>
<div
ref="tableau"
style="width:800px; height:700px;"
/>
</div>
</template>
<script>
export default {
name: "TableauWorkbookShow",
props: {
url: {
type: String,
required: true,
},
},
mounted(){
this.initViz();
},
methods: {
initViz() {
// url looks something like this: https://my-server-url/#/site/my-site-name/views/workbook-name/view-name
var viz = new tableau.Viz(this.$refs.tableau, this.url);
}
}
};
</script>
no errors, neither info on the page, anything else i need to consider here ? and should I add Auth tickets to the url to get workbooks or the url as it is now is fine to work?
One way to test would be to use the Embed code directly from the workbook on Server.
Click Share
Then click Copy Embed Code.
Paste this code directly into your html/view. It should have everything included to populate your dashboard into a webpage.
If this works, you know that your overall auth is working and you can troubleshoot the differences of your js to the embed code.
If auth doesn't work you should still see this screen if your js/html is working correctly.

Gatsby site deployed on Netlify not updating data from graphcms

I am a beginner with using Gatsby and graphcms. Fetching data from cms with gatsby development environment is fine, everything good. I have deployed my website on Netlify, when add some new content via cms content is not updating, not fetching.
Component which need content from cms:
import React from "react"
import { StaticQuery, graphql } from "gatsby"
import ServicesMobileProduct from "./ServicesMobileProduct"
const ProductsMobile = () => (
<StaticQuery
query={graphql`
{
product {
products {
id
productName
description
price
amount
}
}
}
`}
render={({ product: { products } }) => (
<>
{products.map(({ productName, description, price, amount, id }) => (
<ServicesMobileProduct
key={id}
productName={productName}
description={description}
price={price}
amount={amount}
/>
))}
</>
)}
/>
)
export default ProductsMobile
Gatsby is a static site generator, this means that in the build/develop time it gathers all data from CMS, markdown, JSON, or other data sources and creates the public HTML output in /public folder. More or less following this simplified schema:
Generally, once the site is built, you need to redeploy it to update, create, or delete content because the site is not updated with these CMS new changes.
What you are trying to achieve is called webhook. A webhook is a way for an application to notify another application when a new event has occurred in real-time such us a creation, deletion, or modification of the content from a source.
In Gatsby, some sources (like DatoCMS) exposes a webhook, but this only works under development mode. Any CMS change will trigger a gatsby develop command to refresh the content. Of course, it's extremely not recommended to upload a site live in gatsby develop mode only to achieve an automated refresh.
In build mode, the idea is quite similar but instead of running a gatsby develop command, you will need to trigger a gatsby build + deploy. If you are using any continuous deployment tool (CD), such as Netlify, you can easily achieve this. If you are using a continuous integration (CI) tool, such as Jenkins, you need to configure a pipeline to achieve it.
Another way to achieve what you want is to create an asynchronous JavaScript request to an external API or data source that populates your application with the content. This will work in any environment but you will lose all the SEO potential (and other) that Gatsby brings.

How to include reCAPTCHA v3 in the background of pages?

In the reCAPTCHA v3 docs, it says
reCAPTCHA works best when it has the most context about interactions with your site, which comes from seeing both legitimate and abusive behavior. For this reason, we recommend including reCAPTCHA verification on forms or actions as well as in the background of pages for analytics.
How do we run it in the background of pages?
Let's say I have a React app that handles multiple web pages, and for one of my web pages, it is a sign up form where I want to get a risk score when users sign up. When the docs say to run reCAPTCHA in the background on other pages, does that mean it's running on other pages as long as <script src="https://www.google.com/recaptcha/api.js?render=_reCAPTCHA_site_key"></script> is in the header? Or do we need to call grecaptcha.execute(...) on all the other pages, and not just the signup page?
As long as you have the script attached, it will run in the background of pages. You can see that it's running if the reCAPTCHA banner/icon is showing on the page (usually bottom right corner). grecaptcha.execute(...) should be run on a specific action, like when you click a button to sign up for example.
#jojochuu, your answer is exactly right. Thanks for that.
I found another reason to run grecaptcha.execute. Logging. Loading api.js (the second line in the code below) is sufficient to activate recaptcha. It displays the flyout recptcha button.
I chose to add the second script that does call grecaptcha and gets the token. Then I use the token to get the score and any error codes from google. I log that data along with the visitor's IP address and a timestamp so I can see how the score changes over time. I can then compare my logs with access logs and maybe spot some IPs I want to ban. Mostly, I just want to know how score changes. I'll disable the logging by removing the second script block.
This is the best tutorial I found. Combining it with the google docs was enough to learn how to do recaptcha right.
<input type="hidden" id="visitor_ip" value="<?=$visitor_ip; ?>">
<script src="https://www.google.com/recaptcha/api.js?render=public-site-key" async defer></script>
<script>
// This correctly gets the token, but doesn't verify the user response (action).
function execGrecaptcha() {
grecaptcha.ready(function() {
grecaptcha.execute('<?=$settings->recap_public; ?>', {action: '<?=$actionName; ?>'}).then(function(token) {
logRecaptchaResults(token);
});
});
}
// Run after page loaded
window.onload=execGrecaptcha;
// Send token/ip to server for logging via ajax
function logRecaptchaResults(token) {
var vip=document.getElementById('visitor_ip');
$.ajax({
url: "https://<?=HOST_NAME_DOT; ?>domain.com/ajax/logit.php",
type: "get", //send it through get method
data: {
"token": token,
"visitor_ip": vip.value
},
});
}
</script>

Image hosted internally inaccessible on MS Teams client

We have enabled Bot Framework app in our corporate Teams and we want to use AdaptiveCards to present rich content to users. For example, we are sending AdaptiveImage containing url pointing to corporate image store.
Sample code:
new AdaptiveImage
{
Size = AdaptiveImageSize.Small,
Url = new Uri("https://corporate-storage.com/images/image1.png"), // This is image not hosted publicly.
AltText = "Some text"
}
This works fine in WebChat client as the url is just appended to the src attribute of the img HTML tag. However in MS Teams it seems that it is preprocessed by some weird proxy / MITM and the url results in:
https://urlp.asm.skype.com/v1/url/content?url=https%3a%2f%2fcorporate-proxy.com%2fimages%2fimage1.png
When we try to browse the url to see where why the picure is not rendered we see empty page with 502 response code in debugger.
Is there a way how to force MS Teams to not alter src attributes of pictures.
For rendering image in adaptive card, it has to be hosted in public content-delivery network (CDN). Here the official document link.
It worked in WebChat client because in browser your authentication is already cached where as in Teams App there is no cache and the image requires authentication.
You need to host the image in public domain or Azure Blob storage to make it work.
I also have not found a way to resolve that, some gays also ask about this problem.
So, I use tampermonkey to load a JS code piece like this.
// ==UserScript==
// #name New Userscript
// #namespace http://tampermonkey.net/
// #version 0.1
// #description try to take over the world!
// #author You
// #match https://teams.microsoft.com/*
// #icon https://www.google.com/s2/favicons?sz=64&domain=microsoft.com
// #grant none
// ==/UserScript==
(function() {
'use strict';
setInterval(function(){
$('img').each(function(){
if($(this).attr('src').startsWith("https://urlp.asm.skype.com/v1/url/content?url=https%3a%2f%2fp.datadoghq.com")){
let datadogUrl=$(this).attr('src').replace("https://urlp.asm.skype.com/v1/url/content?url=","")
datadogUrl=decodeURIComponent(datadogUrl)
$(this).attr('src', datadogUrl);
}
})
}, 5000);
})();
And use Teams Web, not Teams App.

Google Sheets API: How to "publish to web" for embeddable sheet?

If I wanted to publish a Google Sheets spreadsheet so I could embed it on a page within an iframe, I would manually do the following:
Navigate to Google Drive
Open a spreadsheet
File > Publish To Web > Embed > Copy the generated iframe link into an html file
How would I programmatically achieve the above through the Google Sheets API using JavaScript on the front end? I'm generating spreadsheets on the fly in my application and want to immediately embed them on the page once created.
Once the sheet is created, I can dynamically create an iframe element with the necessary attributes (the sheets ID, among others). That throws an error. From this question, it looks like a sheet needs to have a published: true attribute or something, but that requires using the Drive API - I'm trying to avoid that. Is this possible to handle only through the Sheets API?
After searching through the entire Sheets API, googling, and just general soul-searching, I had no choice but to include the Drive API and use it to do my bidding. Here's the solution I came up with. Hope this helps someone else out there!
Used this script from Google for the client-side JS library in the index.html file:
<body>
...
<script type="text/javascript" src="https://apis.google.com/js/client.js"></script>
</body>
Then for the JS stuff:
// Cache the api's into variables.
var sheets = gapi.client.sheets;
var drive = gapi.client.drive;
// 1. CREATE NEW SPREADSHEET
sheets.spreadsheets.create({
properties: {
title: 'new-sheet'
}
}).then(function(newSpreadSheet) {
var id = newSpreadSheet.result.spreadsheetId;
// 2. PUBLISH SPREADSHEAT VIA DRIVE API
drive.revisions.update({
fileId: id,
revisionId: 1
}, {
published: true, // <-- This is where the magic happens!
publishAuto: true
}).then(function() {
// 3. DISPLAY SPREADSHEET ON PAGE VIA IFRAME
var iframe = [
'<iframe ',
'src="https://docs.google.com/spreadsheets/d/',
id,
'/pubhtml?widget=true&headers=false&embedded=true"></iframe>'
].join('');
// We're using jQuery on the page, but you get the idea.
$('#container').html($(iframe));
});
});
As you have concluded, it is not possible through the Sheets API today and is only possible through the Drive API (using the PATCH https://www.googleapis.com/drive/v3/files/fileId/revisions/revisionId request, documented at https://developers.google.com/drive/v3/reference/revisions/update).

Resources