In my [id].tsx page I have the following meta tag structure
<Head>
<meta property="og:title" content={'품고 - ' + archive.title} key="title" />
<meta property="og:type" content="article" key="type" />
{imageUrl && <meta property="og:image" content={imageUrl} key="image" />}
</Head>
However in my production server, when I scrape an article using the Facebook debugger I get the following error
But when I check for an article in my development server, the proper image shows even though the code is the same as production
I also do have the following line in my _app.tsx file that I think may be causing the error but am not sure
<link rel="canonical" href="https://poomgo.com/" />
And the truly strange thing is that if I share my production article links on kakao, the thumbnail image shows up fine, but on Facebook and LinkedIn, the thumbnail image does not show up properly.
Does anyone know why my meta tags are scraped differently on my production and development servers when the code applied is exactly the same?
How my imageUrl is generated
I get archive data from a third party API (strapi) using useSWR
const { data: archive, error } = useSWR('/archives/' + router.query.id, (url) => {
return axios.get(url).then(res => res.data)
}, {
initialData: props.data
})
I then get my images from the archives and if images exist, I get my imageUrl
const images = archive.images
let imageUrl = ''
if (images && images.length > 0) {
imageUrl = getCloundFrontUrl(images[0].url)
}
I then use the getCloundFrontUrl function to replace the url with my cdn
export const getCloundFrontUrl = (url) => {
return url ? url.replace('poomgo-homepage.s3.ap-northeast-2.amazonaws.com', 'cdn-hp.poomgo.com') : ''
}
Below is the shape of my data
I removed the
<link rel="canonical" href="https://poomgo.com/" />
from my _app.tsx and the issue was resolved. Pretty sure that the code above signalled redirects to my home page from every page on production which caused the wrong og:image
Related
I need to render the title of a post when it's shared via Facebook or in other apps or messages.
I want Something like this:
However, my posts show the actual title of the application, which is not what I want. When shared, I want the exact title of the posts to be dynamically displayed as per the post's meta-tags, not the main description of my application
Do not want something like in the picture below
Using React-helmet
To render the post's title, I am using React-helmet async to change the title and meta tag as client-side rendering at runtime. The changes are visible during post-inspection but not on the page source (Ctrl + U on the post) and social media shares.
My index.html
<title>my title</title>
<meta
name="description"
content="test description"
/>
My code on one of the pages
<Helmet>
<title>{title}</title>
<meta name='description' content={description} />
</Helmet>
I then wrap app.js with the react-helmet as
<HelmetProvider>
<App/>
</HelmetProvider>
You can replicate the issue (based on react-helmet) from this link:
https://preview-react-helmet-meta-ta.samsara-web.pages.dev/discussions/discussions-details/419
Can this issue be fixed with React-helmet?
React-snap
This is another package that has not been updated in the last four years.
To change the source file, it must be rendered from the server. I used react-snap to pre-render the HTML file, however, got the following issue.
The build folder is ready to be deployed.
19:36:10.984 You may serve it with a static server:
19:36:10.984
19:36:10.984 yarn global add serve
19:36:10.984 serve -s build
19:36:10.984
19:36:10.984 Find out more about deployment here:
19:36:10.985
19:36:10.985 https://cra.link/deployment
19:36:10.985
19:36:11.124 $ react-snap
19:36:13.427 🔥 pageerror at /: SyntaxError: Unexpected token '<'
19:36:13.427
19:36:13.528 ️️️💬 console.log at /: Buffered flag does not support the 'longtask' entry type.
19:36:13.634 ️️️💬 console.log at /: ServiceWorker registration successful with scope: http://localhost:45678/
19:36:13.723 ️️️⚠️ warning at /: got 403 HTTP code for https://accounts.google.com/gsi/client
19:36:13.724 ️️️💬 console.log at /: Failed to load resource: the server responded with a status of 403 ()
19:36:13.733 ️️️💬 console.log at /: An <img> element was lazyloaded with loading=lazy, but had no dimensions specified. Specifying dimensions improves performance. See https://crbug.com/954323
19:36:14.638 ️️️💬 console.log at /: Access to XMLHttpRequest at 'https://cloudflareinsights.com/cdn-cgi/rum' from origin 'http://localhost:45678' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://localhost' that is not equal to the supplied origin.
19:36:14.639 ️️️💬 console.log at /: Failed to load resource: net::ERR_FAILED
19:36:19.024 ✅ crawled 52 out of 52 (/)
19:36:19.083
19:36:19.107 error Command failed with exit code 1.
19:36:19.107 info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
19:36:19.127 Failed: build command exited with code: 1
19:36:20.854 Failed: an internal error occurred
My package.json
"scripts": {
"postbuild": "react-snap"
}
My index.js
const MyApp = () => (
<Provider store={store}>
<SWRConfig
value={{
fetcher,
dedupingInterval: 10000,
onError: (error, key) => {
if (error.status !== 403 && error.status !== 404) {
// TODO Implement sentry integration
}
},
onErrorRetry: (error, key, config, revalidate, { retryCount }) => {
if (error.status === 404) return
if (retryCount >= 7) return
setTimeout(() => revalidate({ retryCount }), 5000)
}
}}
>
<ErrorBoundary>
<App />
</ErrorBoundary>
</SWRConfig>
</Provider>
)
const rootElement = document.getElementById('root')
if (rootElement.hasChildNodes()) {
ReactDOM.hydrate(<MyApp />, rootElement)
} else {
ReactDOM.render(<MyApp />, rootElement)
}
On further research, I found that server-side rendering can fix this issue. However, it is challenging to render React apps components server-side. There was a potential solution of using an Express Server with complex configurations, discussed here https://blog.logrocket.com/adding-dynamic-meta-tags-react-app-without-ssr/ .
Currently, I am using React and React-dom version 17.0.2.
One of the example posts one can use for inspection would be https://samsara.social/discussions/discussions-details/215/the-dark-triad-in-primates-mind-machiavellian-inte
or any other post on samsara.social web app.
You have to implement open-graph-tags which has too many types.
<Helmet>
// dynamically creating title and helmet will inject it
<title>{title}</title>
// og stands for open graph
<meta property="og:title" content="Users app" />
</Helmet>
For every article page your meta title and description need to be change with your article title and description so it will render it while you share article links. pass meta tags content properly from your page.
Please tell me why when I refresh a page or if I want to manually enter a link address on my site I get a '404 not found' error. The site is located on github pages. What can I do to correct the bug?
Routing is set up.
<BrowserRouter>
<Switch>
<Route exact path="/event">
<Link><Main /></Link>
</Route>
<Route path="/api/:id">
<Description />
</Route>
</Switch>
</BrowserRouter>
Everything works fine on the localhost.
Tried HashRouter instead of BrowserRouter, but then nothing appears at all.
github pages don't work well for single page application but there is hack around it.
add this script to your index.html in public folder
<script type="text/javascript">
// Single Page Apps for GitHub Pages
// https://github.com/rafrex/spa-github-pages
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
// ----------------------------------------------------------------------
// This script checks to see if a redirect is present in the query string
// and converts it back into the correct url and adds it to the
// browser's history using window.history.replaceState(...),
// which won't cause the browser to attempt to load the new url.
// When the single page app is loaded further down in this file,
// the correct url will be waiting in the browser's history for
// the single page app to route accordingly.
(function (l) {
if (l.search) {
var q = {};
l.search.slice(1).split('&').forEach(function (v) {
var a = v.split('=');
q[a[0]] = a.slice(1).join('=').replace(/~and~/g, '&');
});
if (q.p !== undefined) {
window.history.replaceState(null, null,
l.pathname.slice(0, -1) + (q.p || '') +
(q.q ? ('?' + q.q) : '') +
l.hash
);
}
}
}(window.location))
</script>
and create a custom 404.html in public folder
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Single Page Apps for GitHub Pages</title>
<script type="text/javascript">
// Single Page Apps for GitHub Pages
// https://github.com/rafrex/spa-github-pages
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
// ----------------------------------------------------------------------
// This script takes the current url and converts the path and query
// string into just a query string, and then redirects the browser
// to the new url with only a query string and hash fragment,
// e.g. http://www.foo.tld/one/two?a=b&c=d#qwe, becomes
// http://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe
// Note: this 404.html file must be at least 512 bytes for it to work
// with Internet Explorer (it is currently > 512 bytes)
// If you're creating a Project Pages site and NOT using a custom domain,
// then set segmentCount to 1 (enterprise users may need to set it to > 1).
// This way the code will only replace the route part of the path, and not
// the real directory in which the app resides, for example:
// https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes
// https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe
// Otherwise, leave segmentCount as 0.
var segmentCount = 0;
var l = window.location;
l.replace(
l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +
l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +
(l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +
l.hash
);
</script>
</head>
<body>
</body>
</html>
what this does is that we when refresh the page github actually reaches the server for that specific route but since it's SPA the file won't be available so it send the 404.html page which gets the pathname from the file and calls the index.html page and pastes the pathname there.
I've been trying to connect my AdSense account with my Gatsby blog and it seems impossible. AdSense is asking me to place this code between the head tag of my html
<script data-ad-client="ca-pub-XXXXXXXXXXXXXXXX" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
I've tried gatsby adsense plugins and other things and AdSense keeps telling me the code is not in the website. Since the website is hosted in S3, I downloaded the generated index.html and changed the code and re uploaded it. I think the problem is due to an added attribute called data-checked-head to the script tag, so even though I add the code above, what I see in the browser is this:
<script data-ad-client="ca-pub-XXXXXXXXXXXXXXXX" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" data-checked-head="true"></script>
If this code is what AdSense sees, then of course he doesn't recognize it. Does anyone know what can I do in this case?? Or why is this attribute even there?? Thanks
I can't answer about the details of AdSense but I have had problems with meta tags in the head of HTML myself. Here's two possibilites to debug your code in regards to Gatsby:
Many plugins are disabled by default in development mode. Try gatsby build and gatsby serve and then check if it works with plugins.
Use react-helmet to place your script tag in the head of HTML. Use gatsby build and gatsby serve for testing this as well.
You can use gatsby-plugin-google-adsense for displaying ads on your site.
The best way I found is from this article, which suggest a simple React implementation of Google AdSense.
In your gatsby-ssr.js file:
const React = require('react')
const HeadComponents = [
<script
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXX"
crossOrigin="anonymous"
async
/>,
]
exports.onRenderBody = ({ setHeadComponents }, pluginOptions) => {
setHeadComponents(HeadComponents)
}
Then you create a Banner component to include in your Gatsby.js pages:
const Banner: React.FC<BannerProps> = ({
className,
style,
layout,
format,
client = 'ca-pub-XXXX',
slot,
responsive,
layoutKey,
}) => {
useEffect(() => {
try {
const adsbygoogle = window.adsbygoogle || []
adsbygoogle.push({})
} catch (e) {
console.error(e)
}
}, [])
return (
<div className="banner-container">
<ins
className="adsbygoogle"
style={style}
data-ad-layout={layout}
data-ad-format={format}
data-ad-client={client}
data-ad-slot={slot}
data-ad-layout-key={layoutKey}
data-full-width-responsive={responsive}
/>
</div>
)
}
Full article here.
I am using react helmet and am a bit lost with regards to the server side rendering. If I view elements in google console I can see the title and meta description but when viewing the page source they are not there.
I am using a Node.js backend with express to create an API. The React app is just a frontend application which gets data from the Node.js API.
In React I simply have:
import { Helmet } from "react-helmet";
render() {
return(
<>
<Helmet>
<title>My site title</title>
<meta name="description" content="Helmet application" />
</Helmet>
</>
)
}
The direct link to the server side example shows some code which I don't really know what to do with. I think the word 'server' is throwing me off because I am thinking that I need to put some code on my Node.js server but perhaps that is not the case?
Indeed, Helmet.renderStatic() method will collect all tags corresponding to the page you are requesting.
If you want to see those tags on the server side as well (source code), you need to, in your server file:
Call const helmet = Helmet.renderStatic()
From helmet get helmet.title.toString() and helmet.meta.toString()
Append those to your HTML just like https://github.com/nfl/react-helmet#server-usage As string input describes.
Change index.html to index.php and use PHP in index.php after build. and create a file myMata.php move all old meta tags to myMata.php and make dynamic meta tags using PHP.
view-source:https://www.heinsoe.com
index.php
<html>
<head>
<?php include './myMata.php';?>
//more code
myMata.php
<?php
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$paths = (explode("/", $path));
if (isset($paths[1])) {
switch ($paths[1]) {
case 'blog':
?>
<title>dynamic title</title>
//..... other tag
<?php
break;
case 'contact':
?>
<title>contact</title>
//..... other tag
<?php
break;
default:
http_response_code(404);
break;
}
}
else{
?>
<title>Home</title>
//..... other tag
<?php
}
?>
Can anyone help me regarding how to use meta tags with dynamic value in react js?
Please see the image for my requirement,
I am using the extra metatag html tag here(because react require wrap complete html inside the single tag else it raise error). I can also use div/p any html tag, but is this right way to render the react component? having extra html tag than inside that meta tags. Will this work for SEO?
Please suggested me any other good way to use meta tags manually.
I can see few issues regarding the code which you shared.
Meta tags come under head, but your react components would be rendered in your body tag.
Considering SEO part, google can parse JS now so your tags would be read but bing and if you consider yahoo still cannot still do that( Google also is really not that efficient still, faced too many issues regarding while handling SEO's with single page app)
If your reacts components uses Link to navigate to other components which I am assuming it would it case of SPA it would not work, because crawlers try to reach you page directly.
Now,if you have a single page app with a single component you can try react-helmet , but if it involves multiple components and navigations I would suggest you to go for pre-rendering,maybe using phatom-js or pre-render.io(which indirectly uses phantomjs).
If your only concern is meta tags, then you can embed you meta tags directly into your html code and not in the components. This would really help the crawlers to see the meta tags.
But,if you also want crawlers to see your content, pre-rendering is best solution which I can think of now.
If you are serving your React bundle from a server, you can dynamically generate meta tags on the server.
Essentially, in your public/index.html file you want to replace the metadata with an identifiable string:
<!-- in public/index.html -->
<title>$OG_TITLE</title>
<meta name="description" content="$OG_DESCRIPTION" />
<meta property="og:title" content="$OG_TITLE" />
<meta property="og:description" content="$OG_DESCRIPTION" />
<meta property="og:image" content="$OG_IMAGE" />
And then on the server, you want to replace these strings with the dynamically generated information. Here is an example route with Node and Express:
app.get('/about', function(request, response) {
console.log('About page visited!');
const filePath = path.resolve(__dirname, './build', 'index.html')
fs.readFile(filePath, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
data = data.replace(/\$OG_TITLE/g, 'About Page');
data = data.replace(/\$OG_DESCRIPTION/g, "About page description");
result = data.replace(/\$OG_IMAGE/g, 'https://i.imgur.com/V7irMl8.png');
response.send(result);
});
});
Taken from this tutorial here: https://www.kapwing.com/blog/how-to-add-dynamic-meta-tags-server-side-with-create-react-app/
Create React App produces a static bundle with HTML, JS, and CSS. It can’t possibly give you a dynamic <meta> tag because the result HTML is created ahead of time.
While changing document.title with something like React Helmet makes sense, changing <meta> tags doesn’t make sense unless your app is server rendered. Server rendering is not a supported feature of Create React App so if you want to use it, you might want to check out some alternatives such as Next.js.
That said, if you don’t want full server rendering and only need to change <meta> tags, you could do this by hand as described here.
I hope this helps!
** no need to install express node and all..
** just add react-helmat & must add Helmat-meta tag all routing container. (otherwise its still show home page meta tag)
** react return single element, so you must add into parent element like (div, form)
import { Helmet } from "react-helmet";
import MetaDataJSON from "./MetaDataJSON_File";
constructor(){
this.metaDetails = {};
}
UNSAFE_componentWillMount(){
let curPath = window.location.pathname
this.metaDetails = getMetaData(curPath);
}
export const getMetaData = (pathname) =>{
const metaObj = MetaDataJSON; // import meta json and check the route path is in equal to your meta json file
let metaPath = Object.keys(metaObj);
if (metaPath.indexOf(pathname) >= 0) {
return metaObj[pathname];
}else{
return metaObj["/"];
}
}
// you must add in all component (where routing container)
render(){
return(
<div>
<Helmet>
<title>{this.metaDetails.title}</title>
<meta name="description" content= {this.metaDetails.description}/>
<meta name="keywords" content= {this.metaDetails.keywords} />
</Helmet>
<div>
)
}
There Is a Package Named React-Helmet available it helps to take control over Your Head tags on each route.
Helmet takes plain HTML tags and outputs plain HTML tags. It’s dead simple, and React beginner friendly.
<Helmet>
<title>{context.StoreName}</title>
<meta name="theme-color" content={`${context.ThemeColor}`}/>
</Helmet>
reference - https://codeburst.io/how-to-control-head-tags-in-react-seo-friendly-8264e1194880