I'm trying to create a module that will fire send an event via google analytics' Measurement Protocol API when a file is downloaded. These files are all in the private file system outside of the document root.

hook_file_download looks like a somewhat likely candidate for triggering an http request to google analytics, but since the hook is responsible for access, it seems possible that another module might deny access after this version of the hook is run, and google analytics would get an event even in cases where the download didn't go through. If there a better hook that would be run after all the access check have finished? I should probably mention that I am using the media module.

Supplementarily, the existence of both hook_file_download and hook_file_download_access is confusing since they both claim to control access to files. Is it a correct understanding that hook_file_download_access basically controls whether a user has access in relation to the entity the file is attached to (so likely would control whether the download link is displayed at all or not), and hook_file_download only applies to private files, and checks on access after a request for the file has been made?

Follow Up

I ended up implementing two hooks: hook_file_download and hood_file_transfer which as far as I could tell is undocumented in the drupal api site as a hook. Both of those hooks calls a function passing the $uri parameter which in turn builds the google analytics request and then sends an http request. That seems to cover the two different cases when a file download passes through drupal for my setup.

1 Answer 1


If I recall correctly, there's an access pass before hook_file_download is ever called. hook_file_download is called so you can modify headers, or do a last minute abort on the download.

So on the assumption that no one else is calling that hook (which you should check for the modules you have installed), a hook_file_download implementation is a perfectly fine place to do something like call a Google API. The only caveat is that if you're calling a web service, you want to make sure it doesn't take so long as to screw up the download.

I'm fairly certain that the hook will be called for any file scheme (i.e., "private:", or a custom scheme). You may want to look at the Drupal 7 Example module "File" example, which I believe shows a hook_file_download implementation.

The behavior in Drupal 8 is similar, BTW.

  • Thanks, I've got that written and working, but one of the ways I show files has a url like /file/122018/download?token=m6HpvEZ5 which is different than the other pathauto generated link I have for files. This link seems to never hit hook_file_download. Can you provide any insight into what is happening there? ( The links that do hit that hook look like /system/files/publication_documents/pub/discussion_paper_working_paper/1068/filename.pdf)
    – UltraBob
    Apr 11, 2016 at 13:23
  • It seems to look for a hook called file_transfer, but I don't find any hook_file_transfer in the api docs.
    – UltraBob
    Apr 11, 2016 at 13:28
  • AFAIK, there isn't a hook_file_transfer in Core. Apr 12, 2016 at 23:05
  • AFAIK, there isn't a hook_file_transfer in Core. But as far the URL format you're using for your files, what's generating the "/file/{fid}/download" style URL you're using here? the private: file scheme generates its URLs via code in stream_wrappers.inc in DrupalPrivateStreamWrapper::getExternalUrl(); they have a format like "/system/files/SUB_PATH". If you're directly rendering your files out to the browser (which will not use the same code), then yeah, hook_download will not be called. But since you're rendering out the files yourself, you can call your special code in the same place. Apr 12, 2016 at 23:12
  • As for pathauto: what is a URL like /file/122018/download resolving to? Who is rendering your files to the output stream for you? Apr 12, 2016 at 23:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.