List of recently viewed nodes in Drupal

This tutorial attempts to unveil the beauty of Drupal's modular architecture, which allows for combination of three modules to provide a functionality which would at the first thought require a separate software add-on of its own.

These days, users are provided with a Recently Viewed block on quite a few websites. It's a useful on-site history of last ten or twenty content pages you've viewed, which follows you wherever you're logged in from. Variations exist which combine the list with user's favourite content or recommendations.

The most straightforward approach to implementation of such a feature would be a module built around a database table with three columns -- viewing user's uid, viewed node's nid and date of viewing. The module's hook_nodeapi('view', FALSE, TRUE) implementation would update the history stored in our database table.

Is it really necessary, though, to start writing a module from scratch? Could we possibly use what Drupal project is already offering? With three popular modules which most likely you've had installed already, we can quickly put together a recently viewed list of nodes for each user.

We're going to use Flag module to flag each visited node with a per-user flag. To have it flagged automatically and re-flagged at each consecutive visit of the node, we'll use a little help from Rules module. Finally, to display the user's list of recently viewed content, e.g. in a form of a block, we'll use the must have Views module.

That pretty much sums it up. If you know what I'm talking about and how to make it work by yourself, go ahead. Here's a long version for the rest of you.

Flag module

Flag module is an incredibly useful Drupal module. At first glance, it might seem to be only good for users to bookmark their favourite content. But for website developers it provides great means of grouping content, "marking" it for later use.

Just an example of what you can use it for (apart from bookmarks and recently viewed content) -- on a real estate website I've worked on recently, I used Flag module to implement a Unit comparison feature. User would flag individual living units with an Include in comparison flag and a simple view would render the unit comparison table itself with all flagged nodes' data included.

A very important feature of flags, in addition to linking a node record with a user one, is that it also stores the date and time of when the flagging occurred.

Let's set up a flag we'll to use to "mark" visited nodes as users are browsing our website. Navigate yourself to Administer » Site building » Flags configuration page and add a new flag with settings along these lines:

Flag name
Flag type

Submit. The flag we're creating won't be visible to users and so it doesn't really matter what you use for title and link texts. What's important, though, are the following fields:

Global flag
no (instead, we want a per-user flag)
Roles that may use this flag
authenticated users (or whatever user roles you want to track recently viewed items for)
What nodes this flag may be used on:
Story, Forum and Blog (or any other node types for which you want to keep track of visits)

Like I said, we want to make this flag "automatic" and not visible to users at all.

Display link on node teaser
Display link on node page
Display checkbox on node edit form

Rules module

I haven't used Rules module excessively but I believe it's alright to think of it as of Trigger module on steroids. It lets you define conditionally executed actions based on occurring events. Which is what we need now.

Every time a user views content, we want Rules to flag it with our recently_viewed flag. To preserve the actual viewing order and to have the flagging time updated on each visit, we need to work around a minor Flag module annoyance -- if the node is already flagged, it does not get re-flagged. Thus, the date and time won't get updated. To make it work our way, we unflag the node first, then re-flag it again.

Make your way to Administer » Rules » Triggered rules configuration page and click Add a new rule:

Re-flag node recently_viewed
Content is going to be viewed

Since Flag is smart enough to follow its configuration and will only flag the nodes of allowed types on behalf of allowed users, we don't need to create duplicate Rules conditions. We can set up Rules to flag every node user visits and let Flag decide what will get flagged eventually, based on the flag's settings.

To prevent Rules from re-flagging the nodes each time they appear as teasers in taxonomy pages or items in Views, we want to add a condition to check for a truth value. This way we can make sure the actions only get executed when node is displayed as page:

Select the condition to add
Check a truth value
Truth value
<?php echo $page ?>

Our rule has two actions: unflag the node and flag it again. Add an action:

Select an action to add
Unflag a node

Submit and continue:

Flagged content
viewed content
User on whose behalf to unflag
acting user
Recently viewed
Check access permissions against the user on whose behalf to flag

The second action of our rule is set up the exact same way except for we're flagging this time.

It's important to create the unflag action first and the flag action afterward. The action's Weight field is supposed to allow for action execution reordering, it just doesn't seem to be working for me.

Views module

Finally, to display the list of recently viewed content, we're going to use the almighty Views module. We want to set up a view to contain links of ten nodes most recently flagged with recently_viewed, ordered by recency and displayed in a block.

Click Add in Administer » Site building » Views configuration page to create a view:

View name
View type
Add relationships Flags: Node flag
Include only flagged content
Recently viewed
Current user
Add sort criteria Flags: Flagged time
Sort order
Add fields Node: Title
Link this field to its node
Style: HTML List
Grouping field
List type
Unordered list

That's about it. Just add a block display, save and you're ready to roll. The view will show up in the blocks configuration page, ready for you to add it to the user's account page or display it in sidebar as part of a user's toolbox.

Tips and ideas

I'm using recently viewed content block along with Insert View module to group a couple of useful views into a single Tools block.

The basic functionality outlined above only works for logged in users. If you'd like to have the same feature available for the anonymous users, you might want to have a look at the Session API. Not having used it myself, it seems to integrate with Flag. I'm not sure, though, how anonymous sessions would play with the page cache. It's likely the node viewing event wouldn't fire up on cached nodes and the actions wouldn't get executed.

You can extend the view with a few links and make it work like eBay's Recently viewed items. You can add a link to node's author account or to place a recently viewed item into user's watch list -- implemented using Flag module!

You can create a Recently changed content list with a mere change of Rule's triggering event from Content is going to be viewed to Content is going to be saved.

With another tiny change you can make it display only the current user's recent posts. Each of the three modules we've used today (Flag, Rules, Views) is robust and powerful enough to make their combination each Drupaller's heavyweight tool.

Recently viewed Drupal module9.5 KB


Fantastic article. Extremely

Fantastic article. Extremely helpful and thorough, and helpful also to those who haven't really dived into views, flags, or rules. Very cool.

Jan, you're a Drupal genius.

Jan, you're a Drupal genius. Congrats!

just beautiful, thanks indeed

just beautiful, thanks indeed

really helpful

really helpful tutorial,

So how would you implement

So how would you implement this for anonymous users? i've installed the Sessions API module.

Then change a setting with "Flag" possibly?

Yep, pretty easy! You have to

Yep, pretty easy! You have to be using Flag 2.0, though. After installing SessionAPI, additional settings for anonymous users show up in your flags configuration pages, allowing you to enable flagging by anonymous users.

I am using Flag module

I am using Flag module version, 6.x-1.3, last viewed node is working for authenticated user, i have installed Sesion API module but i didn't find anonymous user roles in Flag config page. under the "Roles that may use this flag:" only authenticated user role is there.

Thana, only Flag module

Thana, only Flag module version 2.0, currently in beta, supports flagging for anonymous users. To be able to use this functionality, please, make sure to upgrade Flag module to the 6.x-2.* line.

Thanks for the article, just

Thanks for the article, just what I needed.

Possible to Create the

Possible to Create the Opposite view?

Is it possible to also create a view to show who has not yet viewed a node?

This article is great!

Thanks much!

Hm... I can think of a way to


I can think of a way to display user's not viewed nodes.

I can even put together a view to list of users who have viewed a given node.

But the list of users who have not yet viewed a certain node I just can't figure out. :-(

Well Dang :) I have this

Well Dang :)

I have this page bookmarked and will post if I have any updates from my end and will check to see if there any possibilities posted here also.

Thank you for your helpful site!

Hi, New article

New article describing about the recently viewed nodes in drupal.You had implemented this using Views module and you had made changes int the views module but i gotta a question that whether this can be implemented without Views module.If so how?

Sure you can. You'll just

Sure you can. You'll just have to reinvent whatever parts of Views I'm using in my tutorial to fetch and display the flagged nodes. Question is, why would you do it?

drupal7 I can't do.

drupal7 I can't do.

Neither I. I'm stucked with

Neither I.
I'm stucked with rules.I can't seem to add the right conditions,especially can't find the right token for anonymous users.Did someone managed to make it work with drupal 7?

Sorry to hear that guys! Just

Sorry to hear that guys! Just like you I've had no problem setting it up for authorized users in Drupal 7, but I hit the wall getting it to work for anonymous users.

Unfortunately the site:current-user data selector in Rules doesn't seem to be supported by SessionAPI.

Please, let me know if you manage to get it working on your end. Cheers!

Since Rules 7.x still has

Since Rules 7.x still has problems triggering actions for anonymous users, I found workaround for this problem in D7:

Do all the same a described in Jan's great tutorial, except for the rules part:

- enable the core "PHP filter" module
- now create a rule:
-- Content is viewed
Condition type
-- Data comparison - > view-mode -> Full content
-- Execute custom PHP code

// Flag API code to execute with this rule:
$flag = flag_get_flag('recently_viewed'); // exact machine name of your flag type
$flag->flag('unflag', $node->nid); // unflag first to refresh the flagging time
$flag->flag('flag', $node->nid);

If the module "Session API" is installed it works like charm for anonymous guests in Drupal 7 this way! (and for authenticeted users anyway)


Wow! Thanks heaps for that,

Wow! Thanks heaps for that, Simon!

Thanks a lot

Thanks a lot Simon!
Unfortunately i can't get this to work anyway.
Adding that condition type gives me an internal server error (ouch...) after chosing view-mode data,and anyway i discovered that an overriding of the node view template via panels (which i did), makes rules not triggering correctly.
So i guess i don't have choice but to wait for a better integration between those two.
(Correct me if i'm wrong please!!! :) )

There is a brandnew patch for

There is a brandnew patch for the entity api module, that makes it work for anonymous users in D7 too! See & download here:

So you can make it work in D7 liked described ins Jans original post now!

BTW: Unfortunately there is a bug in the (d7) flag module, that causes PDO Exceptions from time to time when flagging nodes for anonmyous users.
see here:


Hi! Great tutorial, thank you

Hi! Great tutorial, thank you very much.
In big number of node visits and lot of users - won't it use too much of database space? I mean it probably will store all views from all users - is it somehow possible to flag just those last 20 (for example)... not to flag alllll of the visited nodes?
Or do you think, it won't be a problem?
Anyway thanks for great points!

I ran into this same issue -

I ran into this same issue - removing the flags whose delta (for lack of better terms) is greater than the number of recently viewed products that are displayed to the user.

I have a view that lists the last 5 products viewed so I don't need anything beyond that. What I did was I set up a views bulk operation view pretty much the same as in this tutorial except that I set the Items to display offset to 5, so it lists all of the flagged items after the latest 5.

Then I cloned the rule I created from this tutorial with a flag condition of "User has flagging count of" and selected >= 5. I then added my VBO view to the action which will remove the unneeded flags.

Hope this helps!

Update- What I explained


What I explained above regarding the removal of flags - it ended up not working as expected so I had to implement hook_cron() as follows:

 * Implementation of hook_cron().
function MYMODULE_cron() {
  // this simply trims up the flag_content table so it doesn't get out of hand.
  $flag_id = 2;
  $timestamp = time() - (60 * 60 * 48);
  $sql = "DELETE FROM {flag_content} WHERE fid = '%d' AND timestamp > '%d'";
  $result = db_query($sql, $flag_id, $timestamp);

shawngo, Could you please


Could you please explain in detail how/where to implement your code snippet? I've never added anything to hook_cron(). How or where do I do this?


Mike, You need to create a

Mike, You need to create a custom module that would implement hook_cron() the way shawngo suggested. For information on how to go about creating a module, follow the tutorial at API documentation for hook_cron() can be found at

To preserve the actual

To preserve the actual viewing order and to have the flagging time updated on each visit, we need to work around a minor flag module annoyance if the node is already flagged, it does not get re-flagged.

Thanks a lot for this nice

Thanks a lot for this nice article!

Hello Jan, Today I upgraded

Hello Jan,

Today I upgraded Views for the critical security update to version 6.x-2.14 and now my List of recently viewed nodes is no longer appearing.

Has anyone else experienced this? I don't know what Views is doing differently and don't even know where to start trouble shooting this :-(

If anyone has a solution please post up, thanks!

Update on this: Views 2.15

Update on this: Views 2.15 and also 2.16 came out pretty quickly after v2.14, and when I upgraded from 2.14 to 2.16, suddenly my list of recently viewed nodes was restored. So just as an FYI, in my experience, Views 2.14 is not compatible for some reason with this. So just use a newer version and you should be golden :-D My recently viewed content is running great at Browse to a few product pages and let me know how it looks. Thanks!

Simply superb. I never

Simply superb. I never thought this Flag can do much better unexpected things....

Thanks man, this worked so

Thanks man, this worked so well for me!
I've added the action of sending an email to that rule so I can keep track of what my students are doing! Great job!

This is brilliant; very

This is brilliant; very clever method. Thank you!

Installing the session API module did the trick perfectly for anonymous users- no need for any custom PHP :) Looking at the db table, it's just added another column to flag_table called 'sid', which runs alongside nid. Pretty clever.

Hi, No easier way to achieve


No easier way to achieve this ?


Hi Jan, How would you

Hi Jan,

How would you implement an "Others also viewed these units" block on your real-estate site?



Any idea how would you do the

Any idea how would you do the echo $page truth value in rules 7.2x? there's no truth value (substitute "execute custom php code"?) and no $page variable.

Besides that it still works perfectly.


Hi Raf, I have the same

Hi Raf,

I have the same problem. I can't find the "Check a truth value" under the condition option. I am working on D7 with Rules 7.x-2.1 and Flag 7.x-2.0-beta6. Have you find out the problem?

Thanks in advance.

Hello, Thank you for this

Thank you for this article. I use drupal 6, I followed your setup and it works really great.
Is it possible to make it work with page cache enabled? I want to make a block with latest viewed nodes for anonymous users. I created a block with ajax so it can work on cached pages. Every time I turn caching on, the cached pages are not recorded. Thank you for help.

Seems fair enough to also

Seems fair enough to also mention this simple but handy module:

Yes, I'm using the

Yes, I'm using the Recently_read module, a lot easier hahaha

Hey, I am sorry, a little off topic but


I am in Thailand and want to use a local payment gateway but they only have a module for OsCommerce.

Do you know any reliable coder online and how much do you think could cost a simple payment module to make my Ubercart shop discuss with payment gateway ?

Thank you for your ideas.

Extremely useful and

Extremely useful and carefully selected information.

Blasphemy! LOL Just kidding.

Blasphemy! LOL Just kidding. Ive read similar things on other blogs. Ill take your word for it. Stay solid! your pal.

It’s a really useful posting

It’s a really useful posting for people like me. Site gives new information and trick. It’s very useful for me to use internet, its very necessary for who haven’t really dived into views, flags’. U did a very effort work for building this blog.<a href="" rel="follow"></a>


<a href="" target="_blank">大阪 激安デリヘル</a>
<a href="" target="_blank">大阪 激安デリヘル</a>
<a href="" target="_blank">大阪 激安デリヘル</a>
<a href="" target="_blank">大阪 激安デリヘル</a>
<a href="" target="_blank">大阪 激安デリヘル</a>
<a href="" target="_blank">大阪 風俗</a>
<a href="" target="_blank">大阪 ホテヘル</a>
<a href="" target="_blank">大阪 風俗求人</a>
<a href="" target="_blank">大阪 風俗求人</a>
<a href="" target="_blank">大阪 風俗求人</a>
<a href="" target="_blank">人妻店 求人</a>
<a href="" target="_blank">大阪(大阪全域・堺東・梅田・日本橋)の風俗,デリヘル,ホテヘル高収入求人情報サイト 25歳~30代の女性に特化した風俗求人デリヘルバイト情報サイト</a>
<a href="" target="_blank">大阪 高収入</a>
<a href="" target="_blank">大阪(大阪全域・堺東・梅田・日本橋)風俗求人デリヘルバイトの高収入求人情報サイトです。</a>

Very interesting, thank you !

Very interesting, thank you !

Very Good and Useful Tips.

Very Good and Useful Tips.

"Beauty Tutorial Portal" offers a variety of beauty tips to enhance and nourish the beautiful you in the comfort of your home. Try them, improve your looks and step out with greater confidence. Timeless, proven beauty secrets that nurture and enhance beauty are mostly made from natural products. Beauty solutions for a radiant face, glowing skin, silky hair and a beautiful body using easily available natural products are presented to you in simple, do-it-yourself steps.

Read more:

You blog has been a great

You blog has been a great help for me to move on a paperless lifestyle. I'm so grateful to you to share such an interesting posts. I'm making a progress on writing stuffs, and wish i could follow the similar was as that of you.

I really enjoy reading

I really enjoy reading !

Good post

Good post