Analytics API
Comprehensive guide to the ThoughtFarmer Analytics API endpoints for retrieving user activity, page engagement, and search statistics.
Table of Contents
- Overview
- Authentication
- Async Report Pattern
- Pagination
- User Endpoints
- Action Endpoints
- Report Endpoints
- Request Models
- Response Models
- Common Use Cases
- Performance Considerations
- Best Practices
- PageType Reference
Overview
The Analytics API provides programmatic access to ThoughtFarmer usage statistics, including:
- User activity metrics (views, edits, creates, comments, likes, etc.)
- Page engagement data (views, downloads, media plays, etc.)
- Search behavior analytics
- Content ownership and authorship information
All endpoints follow a consistent async report pattern to handle both quick and long-running queries.
Authentication
All Analytics API endpoints require authentication using the PublicApi policy. Include your API credentials in the request headers.
Base URL: /api/stats
Async Report Pattern
All POST endpoints in the Analytics API use an asynchronous report generation pattern to handle queries that may take varying amounts of time to process.
How It Works
- Submit Request: Make a POST request to initiate report generation
-
Immediate Response (< 60 seconds):
{ "items": [...], "pageNumber": 0, "pageSize": 100, "totalItems": 250 } -
Delayed Response (> 60 seconds):
{ "status": "InProgress", "reportId": 12345 } -
Poll for Results: Use the GET endpoint with the
reportIdto retrieve results- Continue polling until
statusbecomes"Succeeded" - The full report data will be included once complete
- Continue polling until
Example Workflow
// Initial POST request
const response = await fetch('/api/stats/users/123/mostliked', {
method: 'POST',
body: JSON.stringify({ pageSize: 100, pageNumber: 0 })
});
const data = await response.json();
if (data.status === 'InProgress') {
// Poll using the reportId
const pollReport = async (reportId) => {
const pollResponse = await fetch(`/api/stats/users/123/mostliked/${reportId}`);
const pollData = await pollResponse.json();
if (pollData.status === 'InProgress') {
// Wait and poll again
setTimeout(() => pollReport(reportId), 2000);
} else {
// Report is ready
processResults(pollData);
}
};
pollReport(data.reportId);
} else {
// Results returned immediately
processResults(data);
}
Pagination
Most endpoints return paginated results using the PagedItems<T> structure.
Pagination Parameters
- PageNumber: Zero-based page index (default: 0)
- PageSize: Number of items per page (default: configured default, max: configured max)
Pagination Response
{
"items": [...],
"pageNumber": 0,
"pageSize": 100,
"totalItems": 250,
"hasMore": true
}
- hasMore: Boolean indicating if more pages exist beyond the current page
User Endpoints
GET User's Most Liked Pages
Retrieves pages created by a user, ordered by the number of likes received.
Endpoint: POST /api/stats/users/{userId}/mostliked
Request Body:
{
"pageSize": 100,
"pageNumber": 0
}
Response: PagedItems<StatsContentAndCount>
{
"items": [
{
"content": {
"contentId": 456,
"title": "Company Announcements",
"url": "/announcements/page-456"
},
"count": 42
}
],
"pageNumber": 0,
"pageSize": 100,
"totalItems": 25
}
Polling: GET /api/stats/users/{userId}/mostliked/{reportId}
Use Cases:
- Identify a user's most popular content
- Recognize top content creators
- Build user achievement dashboards
GET User's Most Commented Pages
Retrieves pages created by a user, ordered by the number of comments received.
Endpoint: POST /api/stats/users/{userId}/mostcommented
Request/Response: Same structure as Most Liked Pages
Polling: GET /api/stats/users/{userId}/mostcommented/{reportId}
Use Cases:
- Find content that generates discussion
- Identify engaging topics
- Measure content interaction quality
GET User's Owned Pages
Retrieves all pages owned by a user with optional sorting.
Endpoint: POST /api/stats/users/{userId}/owned
Request Body:
{
"pageSize": 50,
"pageNumber": 0,
"orderBy": "ModifiedDate",
"sortDirection": "Descending"
}
OrderBy Options:
-
Title- Alphabetical by title -
CreatedDate- Date page was created -
ModifiedDate- Date page was last modified -
PublishedDate- Date page was published -
PageType- Content type
SortDirection: Ascending or Descending
Response: PagedItems<IContent> (full content objects)
Polling: GET /api/stats/users/{userId}/owned/{reportId}
Use Cases:
- Audit user-created content
- Content ownership reports
- User portfolio views
Action Endpoints
Security Group IDs
When filtering by security groups, use these standard IDs:
- 1 - Admin user group
- 3 - All Registered Users
Common Filter Pattern: To get all registered users who are NOT admins:
{
"securityGroupIds": [3],
"excludeSecurityGroupIds": [1]
}
This pattern is useful for generating reports that focus on regular user activity while excluding administrative actions.
Page Types
When filtering by content type, use these PageType values (see PageType reference for complete list):
Common Content Types:
- 1 - Page (regular page)
- 9 - Forum (forum)
- 11 - Post (individual blog post)
- 15 - Document (file/document) - This includes media files like mp4.
- 26 - ForumTopic (forum discussion)
- 30 - MicroBlogEntry (update/shoutout)
- 14 - CalendarEvent
Containers & Structure: Typically the content within these containers is more desirable to filter on (e.g. Document would be the images inside a PhotoGallery, Post would be the posts inside a NewsBlog, etc...)
- 2 - Section (section/space)
- 8 - NewsBlog (News/Blog landing page)
- 10 - Group (group space)
- 27 - Folder (document folder)
- 28 - Home (home page)
- 7 - PhotoGallery
Links & Media:
- 3 - Link (internal link)
- 4 - ExternalLink
User-Related:
- 20 - Profile (user profile)
- 23 - ProfileRoot (Employee Directory)
Other numeric values represent internal page types not supported by this API.
GET User Actions (Bulk)
Retrieves aggregated user activity statistics with advanced filtering.
Endpoint: POST /api/stats/actions/user
Request Body:
{
"userIds": [101, 102, 103],
"excludeUserIds": [999],
"groupIds": [5],
"securityGroupIds": [10],
"contentIds": [456, 789],
"pageTypes": [8, 9],
"sectionIds": [20],
"ownedBy": [101],
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-12-31T23:59:59Z",
"includeUserGroups": true,
"pageSize": 100,
"pageNumber": 0
}
Filter Parameters:
- UserIds: Include specific users
- ExcludeUserIds: Exclude specific users
- GroupIds: Filter by user group membership
- ExcludeGroupIds: Exclude users in specific groups
- SecurityGroupIds: Filter by security group membership (1 = Admin, 3 = All Registered Users)
- ExcludeSecurityGroupIds: Exclude security group members (1 = Admin, 3 = All Registered Users)
- ContentIds: Filter actions on specific content
- ExcludeContentIds: Exclude actions on specific content
- PageTypes: Filter by content types - array of numeric PageType values (see Page Types)
- ExcludePageTypes: Exclude specific content types - array of numeric PageType values
- SectionIds: Filter by section/space
- ExcludeSectionIds: Exclude specific sections
- OwnedBy: Filter actions on content owned by specific users
- ExcludeOwnedBy: Exclude content owned by specific users
- OwnedByGroupMembers: Filter by content owned by group members
- ExcludeOwnedByGroupMembers: Exclude content owned by group members
- OwnedBySecurityGroupMembers: Filter by content owned by security group members
- ExcludeOwnedBySecurityGroupMembers: Exclude content owned by security group members
- StartDate: Activity start date (defaults to 1900-01-01)
- EndDate: Activity end date (defaults to 3000-01-01)
- IncludeUserGroups: Include user group membership in response
Response: PagedItems<StatsUserActions>
{
"items": [
{
"fullName": "John Smith",
"userId": 101,
"edits": 45,
"profileEdits": 2,
"creates": 12,
"searches": 156,
"comments": 89,
"likes": 234,
"bookmarks": 23,
"blogPosts": 5,
"forumPosts": 8,
"forumComments": 34,
"microBlogEntry": 67,
"attachments": 15,
"groupCount": 3,
"pollVotes": 11,
"follows": 45,
"mentions": 28,
"shoutOuts": 12,
"shoutOutsReceived": 18,
"profileCompletePercent": 85.5,
"views": 1245,
"uniqueViews": 892,
"downloads": 67,
"uniqueDownloads": 45,
"startPlays": 23,
"uniqueStartPlays": 18,
"finishPlays": 15,
"uniqueFinishPlays": 12,
"mediaCompletions": 10,
"uniqueMediaCompletions": 8,
"groups": [...]
}
],
"pageNumber": 0,
"pageSize": 100,
"totalItems": 50
}
Polling: GET /api/stats/actions/user/{reportId}
Use Cases:
- Department activity reports
- User engagement leaderboards
- Track user contributions by content type
- Measure community participation
Note: This endpoint does not support includeNoActionUsers, includeUserGroups, includeTreePath, or includeLastPageActionDate. To use these advanced options, use the /api/stats/report endpoint instead with reportsToGenerate: ["User"].
Example Queries:
Get all blog post authors' activity in Marketing group:
{
"groupIds": [5],
"pageTypes": [8],
"startDate": "2024-01-01T00:00:00Z"
}
(PageType 8 = NewsBlog)
Find most active users excluding admins:
{
"securityGroupIds": [3],
"excludeSecurityGroupIds": [1],
"startDate": "2024-01-01T00:00:00Z",
}
(Returns all registered users who are not admins)
GET User Actions (Single User)
Retrieves detailed activity statistics for a specific user.
Endpoint: POST /api/stats/actions/user/{userId}
Request Body:
{
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-12-31T23:59:59Z"
}
Response: StatsUserActions (single user object, same structure as above)
Polling: GET /api/stats/actions/user/{userId}/{reportId}
Use Cases:
- Individual user activity dashboards
- User contribution summaries
- Personal analytics
GET Page Actions
Retrieves page engagement statistics with advanced filtering to only look at pages published\created in a specific date range.
Endpoint: POST /api/stats/actions/page
Request Body:
{
"contentIds": [456, 789],
"pageTypes": [8, 1],
"sectionIds": [20],
"userIds": [101],
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-12-31T23:59:59Z",
"createdAfter": "2024-01-01T00:00:00Z",
"createdBefore": "2024-12-31T23:59:59Z",
"publishedAfter": "2024-01-01T00:00:00Z",
"publishedBefore": "2024-12-31T23:59:59Z",
}
Additional Filters (beyond User Actions):
- CreatedAfter: Only pages created after this date
- CreatedBefore: Only pages created before this date
- PublishedAfter: Only pages published after this date
- PublishedBefore: Only pages published before this date
Response: PagedItems<StatsPageActions>
{
"items": [
{
"contentId": 456,
"url": "/announcements/page-456",
"title": "Q4 Results",
"pageType": "BlogPost",
"pageTypeName": "Blog Post",
"views": 1245,
"uniqueViews": 892,
"creates": 1,
"edits": 5,
"downloads": 67,
"uniqueDownloads": 45,
"startPlays": 23,
"uniqueStartPlays": 18,
"finishPlays": 15,
"uniqueFinishPlays": 12,
"mediaCompletions": 10,
"uniqueMediaCompletions": 8,
"likes": 42,
"follows": 28,
"comments": 34,
"bookmarks": 15,
"shares": 8,
"lastViewed": "2024-10-02T14:30:00Z",
"lastDownloaded": "2024-10-01T09:15:00Z",
"modifiedDate": "2024-09-15T10:00:00Z",
"isArchived": false,
"isPublished": true,
"owner": {
"userId": 101,
"fullName": "John Smith"
},
"treePath": [...],
"publishedDate": "2024-09-01T08:00:00Z",
"totalActions": 1467
}
],
"pageNumber": 0,
"pageSize": 100,
"totalItems": 75
}
Polling: GET /api/stats/actions/page/{reportId}
Use Cases:
- Most viewed content reports
- Content ROI analysis
- Media engagement tracking
- Identify stale content
- Content performance dashboards
Note: This endpoint does not support includeNoActionUsers, includeUserGroups, includeTreePath, or includeLastPageActionDate. To use these advanced options, use the /api/stats/report endpoint instead with reportsToGenerate: ["Page"].
Example Queries:
Find most viewed regular pages starting from a specific date: You can calculate a date based on the current date to get the last 30 days for example.
{
"pageTypes": [1],
"startDate": "2024-09-03T00:00:00Z",
}
(PageType 1 = Page)
GET Search Actions
Retrieves search query data showing what users are searching for.
Endpoint: POST /api/stats/actions/search
Request Body:
{
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-12-31T23:59:59Z",
"userIds": [101, 102],
"excludeUserIds": [999]
}
Response: PagedItems<StatsSearchActions>
{
"items": [
{
"fullName": "John Smith",
"term": "quarterly budget",
"date": "2024-10-02T14:23:45Z",
"nextAction": "ViewPage",
"nextActionData": "456",
"nextActionDate": "2024-10-02T14:24:12Z"
}
],
"pageNumber": 0,
"pageSize": 100,
"totalItems": 523
}
Response Fields:
- fullName: User who performed the search
- term: Search query entered
- date: When the search was performed
- nextAction: What the user did after searching
- nextActionData: Data related to the next action (e.g., content ID)
- nextActionDate: When the next action occurred
Polling: GET /api/stats/actions/search/{reportId}
Use Cases:
- Understand user search behavior
- Identify content gaps
- Improve search relevance
- Track search-to-action conversion
- Discover trending topics
Example Queries:
Find failed searches (no next action):
{
"startDate": "2024-09-01T00:00:00Z"
}
(Filter results where nextAction is null or empty)
Popular search terms by department:
{
"groupsIds": [101, 102, 103],
"startDate": "2024-01-01T00:00:00Z",
}
Report Endpoints
Generate Comprehensive Report
Creates a combined report with user and/or page statistics using advanced filters.
Endpoint: POST /api/stats/report
Request Body:
{
"userFilters": {
"userIds": [101, 102],
"groupIds": [5],
"securityGroupIds": [10],
"includeInactive": false
},
"contentFilters": {
"contentIds": [456],
"pageTypes": [8],
"sectionIds": [20],
"ownedBy": [101],
"createdAfter": "2024-01-01T00:00:00Z",
"publishedAfter": "2024-01-01T00:00:00Z"
},
"userFilterId": "guid-123",
"contentFilterId": "guid-456",
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-12-31T23:59:59Z",
"reportsToGenerate": ["User", "Page"],
"includeNoActionUsers": false,
"includeUserGroups": true,
"includeTreePath": true,
"includeLastPageActionDate": true
}
Request Parameters:
- userFilters: User filtering criteria (see StatsUserFilterRequest)
- contentFilters: Content filtering criteria (see StatsContentFilterRequest)
- userFilterId: Saved filter GUID (optional)
- contentFilterId: Saved filter GUID (optional)
- startDate: Report period start
- endDate: Report period end
- reportsToGenerate: Array of report types ("User", "Page", or both) - defaults to both
- includeNoActionUsers: Include active users with zero activity in the date range ⚠️ Significantly increases processing time
- includeUserGroups: Include user group membership data ⚠️ Significantly increases processing time
- includeTreePath: Include content hierarchy paths ⚠️ Significantly increases processing time
- includeLastPageActionDate: Include last action timestamp for pages ⚠️ Significantly increases processing time
⚠️ Important: The parameters includeNoActionUsers, includeUserGroups, includeTreePath, and includeLastPageActionDate are ONLY available on the /api/stats/report endpoint. They are not supported on other endpoints like /api/stats/actions/user or /api/stats/actions/page.
When you need these advanced options, use the /api/stats/report endpoint with appropriate reportsToGenerate values instead of the individual action endpoints.
Performance Note: The parameters marked with ⚠️ require additional post-processing steps to fetch related data. When these are enabled, report generation may take significantly longer. Use these options judiciously - only enable them when the additional data is actually needed for your use case.
Response: Combined report object with both user and page data
{
"userReport": {
"items": [...],
"totalItems": 50
},
"pageReport": {
"items": [...],
"totalItems": 125
}
}
Polling: GET /api/stats/report/{reportId}
Use Cases:
- Executive summary dashboards
- Quarterly activity reports
- Department performance analysis
- Content audit reports
- Custom analytics dashboards
Request Models
RequestIndexing
{
"pageSize": 100,
"pageNumber": 0
}
RequestOwnedPages
{
"pageSize": 100,
"pageNumber": 0,
"orderBy": "ModifiedDate",
"sortDirection": "Descending"
}
RequestIndexStartEndDate
{
"pageSize": 100,
"pageNumber": 0,
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-12-31T23:59:59Z"
}
StatsActionsRequest
See "GET User Actions (Bulk)" for full structure.
StatsPageActionsRequest
Extends StatsActionsRequest with additional fields:
createdAftercreatedBeforepublishedAfterpublishedBefore
StatsSearchReportRequest
{
"startDate": "2024-01-01T00:00:00Z",
"endDate": "2024-12-31T23:59:59Z",
"userIds": [101],
"excludeUserIds": [999],
"pageSize": 100,
"pageNumber": 0
}
StatsReportRequest
See "Generate Comprehensive Report" for full structure.
Response Models
PagedItems
{
"items": [],
"pageNumber": 0,
"pageSize": 100,
"totalItems": 250,
"hasMore": true
}
StatsContentAndCount
{
"content": { /* IContent object */ },
"count": 42
}
StatsUserActions
See "GET User Actions (Bulk)" response for full structure.
Key Metrics:
- Content Actions: Creates, Edits, BlogPosts, ForumPosts, MicroBlogEntry, Attachments
- Engagement: Comments, Likes, Bookmarks, Follows, Mentions, ShoutOuts
- Consumption: Views, UniqueViews, Downloads, UniqueDownloads
-
Media: StartPlays, FinishPlays, MediaCompletions (with unique variants)
- FinishPlays only tracks if the user got to the end of a video. It does not factor in skips. So they could have skipped from the beginning to the end and it would still count as a FinishPlay.
- MediaCompletions is a newer metric. It tracks while a user is actively watching a video and will trigger a MediaCompletion when they have watched 95% of a video. This action is not available before July 2025.
- Other: Searches, PollVotes, ProfileCompletePercent, GroupCount
StatsPageActions
See "GET Page Actions" response for full structure.
Key Metrics:
- Content Info: ContentId, Url, Title, PageType, Owner
- Engagement: Likes, Comments, Follows, Bookmarks, Shares
- Consumption: Views, UniqueViews, Downloads, UniqueDownloads
- Media: StartPlays, FinishPlays, MediaCompletions (with unique variants)
- Activity: Creates, Edits, LastViewed, LastDownloaded
- Status: IsArchived, IsPublished, ModifiedDate, PublishedDate
StatsSearchActions
{
"fullName": "John Smith",
"term": "budget report",
"date": "2024-10-02T14:23:45Z",
"nextAction": "ViewPage",
"nextActionData": "456",
"nextActionDate": "2024-10-02T14:24:12Z"
}
Common Use Cases
1. Find Top Content Creators
POST /api/stats/actions/user
{
"startDate": "2024-01-01T00:00:00Z",
"pageSize": 10
}
// Sort by creates in your application
2. Identify Inactive Users
Find active users who had no activity in a specific date range:
POST /api/stats/report
{
"userFilters": {
"securityGroupIds": [3],
"excludeSecurityGroupIds": [1]
},
"startDate": "2024-09-01T00:00:00Z",
"endDate": "2024-10-03T00:00:00Z",
"reportsToGenerate": ["User"],
"includeNoActionUsers": true
}
// Returns all registered users (excluding admins) including those with zero activity
// Filter results on the client where all action counts are 0 to identify inactive users
Note: includeNoActionUsers is only available on /api/stats/report endpoint. It returns active users who have not logged in or performed any actions during the specified date range.
3. Content Performance Report
POST /api/stats/actions/page
{
"sectionIds": [20],
"publishedAfter": "2024-01-01T00:00:00Z",
"pageSize": 50
}
// Sort by totalActions or views
4. Video Engagement Analysis
POST /api/stats/actions/page
{
"pageTypes": ["MediaPlayer"],
"startDate": "2024-01-01T00:00:00Z"
}
// Calculate completion rates: finishPlays / startPlays
5. Search Effectiveness
POST /api/stats/actions/search
{
"startDate": "2024-09-01T00:00:00Z",
"pageSize": 100
}
// Analyze nextAction patterns to identify failed searches
6. Department Activity Dashboard
POST /api/stats/report
{
"userFilters": {
"groupIds": [5]
},
"startDate": "2024-01-01T00:00:00Z",
"reportsToGenerate": ["User", "Page"],
"includeUserGroups": true,
"includeTreePath": true
}
Note: Advanced options like includeUserGroups and includeTreePath are only available on the /api/stats/report endpoint.
7. Most Engaging Content by Type
POST /api/stats/actions/page
{
"pageTypes": [8],
"startDate": "2024-01-01T00:00:00Z",
"pageSize": 20
}
// Sort by comments + likes in your application
// PageType 8 = NewsBlog (blog posts)
8. User Contribution Portfolio
POST /api/stats/users/{userId}/owned
{
"orderBy": "ModifiedDate",
"sortDirection": "Descending",
"pageSize": 50
}
Error Responses
400 Bad Request
{
"error": "PageNumber cannot be less than 0"
}
404 Not Found
{
"status": "NotFound",
"reportId": 12345,
"message": "Page number out of range"
}
404 Report Not Found
{
"status": "NotFound",
"reportId": 12345
}
Performance Considerations
Several report options can significantly impact processing time. Understanding these trade-offs helps you design efficient integrations.
High-Impact Options (Report Endpoint Only)
Important: These options are ONLY available on /api/stats/report. They are not supported on individual action endpoints.
The following options require additional post-processing steps and can substantially increase report generation time:
-
includeNoActionUsers - Fetches active users with zero activity in the date range
- ⚠️ Adds database queries for inactive users
- Use only when you need to identify users who haven't logged in during a specific period
- Returns active users with zero action counts in the specified date range
- Consider filtering by date ranges to reduce scope
-
includeUserGroups - Adds user group membership data
- ⚠️ Requires additional queries for each user's group memberships
- Use when group analysis is essential
- Can multiply processing time with large user bases
- Only available with
reportsToGenerate: ["User"]or both
-
includeTreePath - Includes content hierarchy paths
- ⚠️ Fetches ancestor pages for each content item
- Use when you need full breadcrumb paths
- Impact scales with content depth and volume
- Only available with
reportsToGenerate: ["Page"]or both
-
includeLastPageActionDate - Adds last action timestamps
- ⚠️ Requires additional timestamp calculations per page
- Use when recency analysis is needed
- Can double processing time for page reports
- Only available with
reportsToGenerate: ["Page"]or both
Optimization Strategies
- Start Simple: Begin with basic queries, add expensive options only when needed
- Test Performance: Run test queries before scheduling recurring reports
- Use Narrow Filters: Limit scope with date ranges, sections, or user groups
- Consider Alternatives: Sometimes multiple smaller queries are faster than one large query with all options enabled
- Monitor Timeout Patterns: If reports consistently exceed 60 seconds, review which options are enabled
When Reports Will Exceed 60 Seconds
Reports are more likely to trigger the async pattern (InProgress status) when:
- Processing thousands of users or pages
- Multiple high-impact options are enabled simultaneously
- Date ranges span years of activity
- Filtering includes large sections or many groups
Best Practices
- Implement Polling Logic: Always design clients to handle both immediate and delayed responses
- Use Appropriate Page Sizes: Balance between fewer requests and payload size
- Leverage Filters: Use inclusion/exclusion filters to reduce data volume
- Cache Results: Store report results locally to minimize API calls
- Monitor Report Status: Implement reasonable polling intervals (2-5 seconds recommended)
- Handle Timeouts: Implement retry logic for network failures
- Validate Date Ranges: Ensure startDate < endDate to avoid empty results
- Use Saved Filters: Utilize userFilterId/contentFilterId for complex recurring reports
- Disable Unnecessary Options: Only enable includeUserGroups, includeTreePath, includeLastPageActionDate, or includeNoActionUsers when the data is required
-
Test Before Scheduling: Run ad-hoc queries to understand performance characteristics before setting up automated reports
Support
For additional information and support, refer to the Stats API public article or contact your ThoughtFarmer administrator.
Comments
0 comments
Please sign in to leave a comment.