In this post we will talk about Differential Query in Graph.

What is Differential Query

Differential Query allows Apps to query for changes that occurred on a given tenant in AAD.

This functionality is especially useful when an App needs to track changes that occurred on tenant in AAD in order to perform App specific operations. It also allows Apps which implement it own data store to effectively integrate with AAD by synchronizing changes from AAD to App's data store.

How to start using Differential Query

As a starting point, App needs to learn about all changes occurred on a given tenant since the tenant was created in AAD. Here is how an App can perform initial Differential Query request:


deltaLink parameter indicates this request to be a Differential Query. And deltaLink parameter with no assigned value indicates that this is an initial Differential Query request.

Differential Query paged responses contain all changes that occurred on the tenant until last page of changes is returned:

  "odata.metadata": "$metadata#directoryObjects",

  # This is the nextLink to be used for the next query
  "aad.nextLink": " [Truncated]",
  "value": [

    # User object for John Smith
      "odata.type": "Microsoft.WindowsAzure.ActiveDirectory.User",
      "objectType": "User",
      "objectId": "dca803ab-bf26-4753-bf20-e1c56a9c34e2",
      "accountEnabled": true,
      "displayName": "John Smith",
      "givenName": "John",
      "mailNickname": "johnsmith",
      "passwordPolicies": "None",
      "surname": "Smith",
      "usageLocation": "US",
      "userPrincipalName": ""

aad.nextLink property indicates that there are more changes on the tenant and that the App should perform subsequent Differential Query request right away and pass aad.nextLink property value from the response as deltaLink parameter value (note that api-version needs to be appended as a request parameter):

  GET [Truncated] 

If a response contains aad.deltaLink property, it indicates that no more changes exist on the AAD tenant in AAD.

  "odata.metadata": "$metadata#directoryObjects",

  # This is the deltaLink to be used for the next query
  "aad.deltaLink": " [Truncated]",
  "value": [

    # Group object for IT Administrators
      "odata.type": "Microsoft.WindowsAzure.ActiveDirectory.Group",
      "objectType": "Group",
      "objectId": "7373b0af-d462-406e-ad26-f2bc96d823d8",
      "description": "IT Administrators",
      "displayName": "Administrators",
      "mailNickname": "Administrators",
      "mailEnabled": false,
      "securityEnabled": true

Subsequent Differential Query response will contain no changed entities until more changes are made on the tenant. At this point, App should store aad.deltaLink value locally and use it in subsequent Differential Query request. This allows the App to come back after a certain interval and issue incremental Differential Query request. Incremental Differential Query request can be repeated for as long as the App is interested to learn about changes on the tenant (and is authorized to provide services on this tenant).

Differential Query response semantics

There are some key differences in the response structure that set Differential Query apart from regular Graph responses we covered in previous posts:

  • response includes deleted objects and deleted links (indicated by "aad.isDeleted" property with value set to true); this is necessary to make sure App can learn about deletes of previously created objects and links
  • response contains entities with only changed properties; e.g. for a new user created since the last time Differential Query request was made, response only includes new user entity with only properties that were set
  • links represented as entities (DirectoryLinkChange entity type); this allows response to contain only changed links. This allows changes on links to be expressed most efficiently so that, for example, if group with large number of member links was changed to add new member, only this new link could be included in Differential Query response.

Differential Query invariants

App developers should consider the following when implementing Differential Query:

  • changes returned by Differential Query represent the state of AAD objects at the time of response
  • changed objects appear approximately in the order in which they occurred in AAD with most-recently changed objects appearing last. This makes it possible for changes to be presented out of order compared to how they initially occurred in AAD
  • App should be prepared to handle a deletion change for an object it was not aware of
  • Differential Query can return a link to a source or target object that has not yet been previously returned
  • App should be prepared for receiving same change in a subsequent response (this is known as change replays); while we make a best effort to reduce replays, they are still possible.


This is it for today. In the next post on Differential Query we will cover a deep dive on Differential Query request/response structure and how App Developers can write simple code to process Differential Query responses.

To learn more about Differential Query, please visit

As always, we are interested to hear your feedback. You can try Differential Query now by visiting Click "Use Demo company"