afterCreate lifecycle for every content type

System Information
  • Strapi Version: 3.5.1

Hello guys!

I’ve watched the following very helpful video.

Is there any way to keep an activity log but for every content type available?

I’ve read here that this could be done with a middleware, has anybody done anything like that before?

Thank you for your time in advance!

Depends on what you mean by “activity log”.

If you mean all the accessed routes, then you could use middleware that runs at the end and stores the logs.

module.exports = strapi => {
  return {
    // can also be async
    initialize() { (ctx, next) => {
        await next();
         await strapi.config.functions['storeLogs'](ctx);


Where storeLogs is your custom function that accepts the ctx param and gets all the necessary data from it ( ctx.state.user - contains the information about logged in user, ctx.request.body - contains the body requests for POST/PUT etc.)

But if you mean the create/update/delete of some entities then you should use webhooks. Build an API that stores all the requests. Now you have an activity log for create/update/delete actions.

Hey guys, I’ve been thinking about the same thing. Well, not exactly the afterCreate lifecycle but about implementing a detailed activity log. I need it to constantly monitor several user’s actions and do some stuff accordingly.

So, I tried to find any information in what direction should I dig - middleware, hooks, or anything else. Admittedly, I thought middleware will be most likely the thing but here I see Sunnyson says that middleware has only limited info about the actions and it would be better to use webhooks.
I find it a bit unhandy to have another small app to collect only “log entries”. The question is if there is a better solution or Hooks + Another app is the best way to receive the information mentioned below:

  • What item was modified and in what collection
  • What was done to the item - disabled, modified fields (possibly, ideally)
  • Date when it was done.

This is probably out of date as the ctx parameter doesn’t return any information related to user or body request at all.

Here is an example of the response after creating a category post.

  request: {
    method: 'PUT',
    url: '/content-manager/collection-types/application::category.category/2',
    header: {
      host: 'localhost:1337',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:91.0) Gecko/20100101 Firefox/91.0',
      accept: '*/*',
      'accept-language': 'en-US,en;q=0.5',
      'accept-encoding': 'gzip, deflate',
      referer: 'http://localhost:1337/dashboard/plugins/content-manager/collectionType/application::category.category/2',
      authorization: 'Bearer xx',
      'content-type': 'application/json',
      origin: 'http://localhost:1337',
      'content-length': '147',
      connection: 'keep-alive',
      'sec-fetch-dest': 'empty',
      'sec-fetch-mode': 'cors',
      'sec-fetch-site': 'same-origin'
  response: {
    status: 200,
    message: 'OK',
    header: [Object: null prototype] {
      vary: 'Origin',
      'access-control-allow-origin': 'http://localhost:1337',
      'access-control-allow-credentials': 'true',
      'strict-transport-security': 'max-age=31536000; includeSubDomains',
      'x-frame-options': 'SAMEORIGIN',
      'content-type': 'application/json; charset=utf-8'
  app: { subdomainOffset: 2, proxy: false, env: 'development' },
  originalUrl: '/content-manager/collection-types/application::category.category/2',
  req: '<original node req>',
  res: '<original node res>',
  socket: '<original node socket>'

ctx and various parts of it are prototypes, you won’t see them if you just console.log(ctx). To actually see/interact with them you would need to log them with console.log(ctx.request.body) ect.

As for the audit log topic, I created an example for this a while back: