Skip to content



Allow custom permissions to be defined. These will appear along with core permissions in the UI and can be granted to user roles. They can be checked using CRM_Core_Permission::check().


These two hooks appear similar, but serve different purposes:

  • hook_civicrm_permission: Defines new permissions. The permission will be fully available in configuration screens for CiviCRM/Drupal/WordPress/etc.
  • hook_civicrm_permissionList: Modifies the list of permissions presented in CiviCRM configuration. For example, this is used to import Drupal/WordPress permissions into CiviCRM configuration screens (without creating a funny loop).


hook_civicrm_permission(array &$permissions): void


  • $permissions: reference to an associative array of custom permissions that are implemented by extensions, modules and other custom code. This will be an empty array unless another implementation of hook_civicrm_permission adds items to it. Items should use the following format:
    function grantprogram_civicrm_permission(array &$permissions): void {
      $permissions['edit grant programs'] = [
        'label' => E::ts('CiviCRM Grant Program: edit grant programs'),
        'description' => E::ts('Create or edit grant programs and their criteria'),
      $permissions['delete in Grant Program'] = [
        'label' => E::ts('CiviCRM Grant Program: delete grant program'), // description is optional, but encouraged


Older extensions may use non-associative arrays (item 0 will be interpreted as 'label' and 1 will be 'description'), or strings (interpreted as 'label'). These formats are deprecated as of 5.71. Extension authors should update to use the new format, which is compatible with all versions of CiviCRM 5.0.0 and up.

Conventions and Tips

  • In the examples, note the convention of using "delete in ComponentName" as the delete permission name.
  • For edit permissions, it is conventional to use the plural, such as "edit your items"; it is normal to use the singular for create permissions, such as "create new item".
  • There is no automatic namespacing for permissions, so one should adopt unique permission names.


The following example adds a permission access CiviMonitor:

function civimonitor_civicrm_permission(array &$permissions): void {
  $permissions['access CiviMonitor'] = [
    'label' => E::ts('Access CiviMonitor'),
    'description' => E::ts('Grants the necessary API permissions for a monitoring user without Administer CiviCRM'),