Your View Counter Is Lying to Google
If your blog counts page views in the same table row as the post, and your structured data publishes a dateModified, there is a good chance those two features are quietly fighting each other — and that every visitor is telling Google your article was rewritten a second ago.
I found this on my own site while moving the blog out of MySQL. Two fetches of the same unchanged article, ninety seconds apart, reported two different modification dates. Nothing had been edited in six months.
How to check your site in thirty seconds
Fetch any article twice and compare the date it claims:
for i in 1 2; do
curl -s https://example.com/blog/some-post \
| grep -o '"dateModified":"[^"]*"'
sleep 3
done
Two identical lines mean you are fine. Two different lines mean every page view is rewriting the timestamp:
"dateModified":"2026-09-18T12:23:43+05:00"
"dateModified":"2026-09-18T12:37:33+05:00"
The same check works on a sitemap. Request it twice and diff the <lastmod> values for a page nobody has touched.
Why it happens
Three ordinary decisions combine into one bug, and each of them is defensible on its own.
First, the schema. Almost every CMS table has some version of this:
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content LONGTEXT NOT NULL,
views INT UNSIGNED NOT NULL DEFAULT 0,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
);
Second, the view counter, which runs on every request to the article:
UPDATE posts SET views = views + 1 WHERE id = ?;
Third, the structured data, which reads the obvious column:
'dateModified' => date('c', strtotime($post['updated_at'])),
ON UPDATE CURRENT_TIMESTAMP does not care which column changed. It fires on any UPDATE that modifies the row and does not set the timestamp explicitly. Incrementing a counter modifies the row. So updated_at stops meaning "when the article last changed" and starts meaning "when someone last read it".
Nothing in that chain looks wrong in isolation. That is what makes it easy to ship and hard to notice — the bug has no symptom on the page itself.
Why it is worth fixing
It is not a penalty, and I would be sceptical of anyone who tells you it is. What it does is spend a signal on nothing.
dateModified is how you tell a search engine that an article has been genuinely revised, which matters for queries where freshness counts. Google's own guidance is that the date should reflect a real change to the content. An article that reports a new modification date on every crawl is not making a strong freshness claim — it is making an unfalsifiable one, and a signal that is always on carries no information.
The sitemap version of this is better documented. Google has been repeatedly explicit that it ignores <lastmod> when it finds a site's values unreliable. A sitemap where every URL claims to have changed today is exactly the pattern that earns that treatment, and once the value is discounted you have lost a genuinely useful way to say "this one really did change, come back".
There is a smaller practical cost too: a row rewritten on every page view is a write on every page view. On shared hosting that is real.
Three ways to fix it
Move the counter out of the row. The cleanest option, because it fixes the cause rather than the symptom. A counter is not an attribute of the article; it is a different fact with a different lifecycle:
CREATE TABLE post_views (
post_id INT UNSIGNED NOT NULL PRIMARY KEY,
views INT UNSIGNED NOT NULL DEFAULT 0
);
INSERT INTO post_views (post_id, views) VALUES (?, 1)
ON DUPLICATE KEY UPDATE views = views + 1;
The posts row is now only written when the post is actually edited, and updated_at goes back to meaning what its name says.
Or suppress the auto-update on that one statement. If you assign the timestamp explicitly, MySQL does not apply ON UPDATE:
UPDATE posts
SET views = views + 1,
updated_at = updated_at -- explicit, so ON UPDATE does not fire
WHERE id = ?;
This is a one-line change and it works, but it relies on every future writer remembering the incantation. Good as a stopgap.
Or stop conflating two different dates. Keep updated_at as a row housekeeping column and add one that means what the schema field means:
ALTER TABLE posts
ADD COLUMN content_updated_at DATETIME NULL AFTER updated_at;
Set it in the editor's save path only, and publish that. This is the most honest model, because "the row changed" and "the article changed" genuinely are different events and always were.
I ended up taking a fourth route, which only makes sense if you are already heading there: my posts are markdown files now, so there is no row to write and the published date comes from front matter. That solved it by deleting the category of problem, which is a luxury, not a general recommendation.
What else to audit while you are in there
Any column with ON UPDATE CURRENT_TIMESTAMP that feeds something outward deserves the same look. The pattern to search for is a timestamp that is written by machines and read by humans or crawlers:
dateModifiedanddatePublishedin Article or BlogPosting schema<lastmod>in your sitemap<pubDate>andlastBuildDatein an RSS feed- "Last updated" lines rendered on the page itself
That last one is the one readers notice. An article stamped "updated 2 minutes ago" that clearly has not been is a small, corrosive credibility problem, and it is the same root cause.
If you want to eyeball your markup rather than grep it, the Schema Markup Generator will show you the shape you should be emitting, the Sitemap Validator checks your lastmod values parse, and the Canonical URL Checker catches the adjacent problem of pages disagreeing about their own address.
Frequently Asked Questions
Does a constantly changing dateModified get my site penalised?
No, and be wary of anyone who says otherwise. It is not a penalty — it is a wasted signal. Google's guidance is that the date should reflect a real change, and a date that always says "just now" gives a search engine no way to tell your genuine updates from your traffic.
Why did my updated_at change when I only touched the views column?
Because ON UPDATE CURRENT_TIMESTAMP fires on any UPDATE that modifies the row, regardless of which column changed. MySQL only skips it when the statement sets that timestamp column explicitly.
Is this the same problem in PostgreSQL?
Not automatically. Postgres has no ON UPDATE CURRENT_TIMESTAMP, so you only get this if someone wrote a trigger that does the same thing — and those triggers usually do fire on any row update, so it is worth checking the trigger body rather than assuming.
Should I just remove dateModified from my structured data?
Only as a last resort. An accurate dateModified is useful, particularly for anything time-sensitive. Omitting it is better than publishing a false one, but fixing the source is better than both and is usually a few lines.
How do I know what the real last-modified date should be?
If the information is genuinely gone, the honest fallback is the publication date — that is what I used when importing these posts, because the stored values had already been corrupted by exactly this bug and there was no way to recover the real ones. Understating freshness costs you far less than inventing it.
Related Tools & Apps
Fruit Slicer
GameSwipe to slice flying fruits — but watch out for bombs!
Social Image Sizer
ToolResize and preview images for all social media platform dimensions.
Duck Shoot
GameAim and click to shoot ducks flying across the sky!
Markdown Studio
AppWrite Markdown with a live preview, document outline, formatting toolbar, readin…
Linux Command Line
LabNavigate the file system, manage files, and learn essential Linux commands in a …
Data Table Generator
ToolGenerate HTML/Markdown/CSV tables from structured data input.
Related Posts
What Breaks in AI-Written Blog Posts
I spent a weekend auditing eight articles a generator had written for this site, expecting to find c…
Building Your First Python Project in VS Code: A Beginner's Guide
In this tutorial, we're going to create a simple Python project using Visual Studio Code (VS Code). …
How to Use Visual Studio Code for Beginners
Visual Studio Code (VS Code) is a popular source code editor developed by Microsoft. It's lightweigh…