easy-umami-js/umami.js
2024-12-07 23:34:10 +00:00

936 lines
No EOL
38 KiB
JavaScript

/**
* @typedef {Object} User
* @property {string} id - The user's unique identifier
* @property {string} username - The user's username
* @property {string} role - The user's role
* @property {Date} createdAt - When the user was created
* @property {boolean} isAdmin - Whether the user has admin privileges
*/
/**
* @typedef {Object} GetTokenResponse
* @property {string} token - Authentication token
* @property {User} user - User information
*/
/**
* @typedef {Object} EventPayload
* @property {string} hostname - Name of host
* @property {string} language - Language of visitor (e.g., "en-US")
* @property {string} referrer - Referrer URL
* @property {string} screen - Screen resolution (e.g., "1920x1080")
* @property {string} title - Page title
* @property {string} url - Page URL
* @property {string} website - Website ID
* @property {string} name - Name of the event
* @property {Object} [data] - Optional additional data for the event
*/
/**
* @typedef {Object} Session
* @property {string} id - Session ID
* @property {string} websiteId - Website ID
* @property {string} hostname - Hostname
* @property {string} browser - Browser name
* @property {string} os - Operating system
* @property {string} device - Device type
* @property {string} screen - Screen resolution
* @property {string} language - Language code
* @property {string} country - Country code
* @property {string} subdivision1 - Region/state code
* @property {string} city - City name
* @property {string} firstAt - First activity timestamp
* @property {string} lastAt - Last activity timestamp
* @property {number} visits - Number of visits
* @property {number} views - Number of page views
* @property {string} createdAt - Creation timestamp
*/
/**
* @typedef {Object} SessionStats
* @property {{ value: number }} pageviews - Pages hits
* @property {{ value: number }} visitors - Number of unique visitors
* @property {{ value: number }} visits - Number of sessions
* @property {{ value: number }} countries - Number of unique countries
* @property {{ value: number }} events - Number of custom events
*/
/**
* @typedef {Object} SessionActivity
* @property {string} createdAt - Activity timestamp
* @property {string} urlPath - URL path
* @property {string} urlQuery - URL query parameters
* @property {string} referrerDomain - Referrer domain
* @property {string} eventId - Event ID
* @property {number} eventType - Event type
* @property {string} eventName - Event name
* @property {string} visitId - Visit ID
*/
/**
* @typedef {Object} SessionProperty
* @property {string} websiteId - Website ID
* @property {string} sessionId - Session ID
* @property {string} dataKey - Property key
* @property {number} dataType - Data type
* @property {string|null} stringValue - String value
* @property {number|null} numberValue - Number value
* @property {string|null} dateValue - Date value
* @property {string} createdAt - Creation timestamp
*/
/**
* @typedef {Object} PropertyCount
* @property {string} propertyName - Name of the property
* @property {number} total - Total count
*/
/**
* @typedef {Object} PropertyValue
* @property {string} value - Property value
* @property {number} total - Total count
*/
class UmamiClient {
/**
* Creates a new UmamiClient instance
* @param {Object} config - Configuration options
* @param {string} config.baseUrl - Base URL for the Umami API
* @param {string} config.username - Umami username
* @param {string} config.password - Umami password
*/
constructor({ baseUrl, username, password }) {
this.baseUrl = baseUrl;
this.username = username;
this.password = password;
this.token = null;
this.tokenExpiry = null;
}
/**
* Makes an authenticated API request
* @private
* @param {string} endpoint - API endpoint
* @param {Object} options - Fetch options
* @returns {Promise<any>} - API response
*/
async #makeAuthenticatedRequest(endpoint, options = {}) {
await this.#ensureValidToken();
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error(`API request failed: ${response.statusText}`);
}
return response.json();
}
/**
* Ensures a valid authentication token exists, obtaining a new one if necessary
* @private
*/
async #ensureValidToken() {
const tokenLifespan = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
const isTokenExpired = !this.tokenExpiry || Date.now() > this.tokenExpiry;
if (!this.token || isTokenExpired) {
await this.authenticate();
}
}
/**
* Formats query parameters for URL
* @private
* @param {Object} params - Query parameters
* @returns {string} - Formatted query string
*/
#formatQueryParams(params) {
return Object.entries(params)
.filter(([_, value]) => value !== undefined)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&');
}
/**
* Authenticates with the Umami API
* @returns {Promise<GetTokenResponse>} Authentication response
* @throws {Error} If authentication fails
*/
async authenticate() {
const response = await fetch(`${this.baseUrl}/api/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: this.username,
password: this.password,
}),
});
if (response.status === 401) {
throw new Error('Authentication failed: Incorrect username or password');
}
if (!response.ok) {
throw new Error(`Authentication failed: ${response.statusText}`);
}
const data = await response.json();
console.log(data)
this.token = data.token;
this.tokenExpiry = Date.now() + (24 * 60 * 60 * 1000); // Set expiry to 24 hours from now
return data;
}
/**
* Verifies the current authentication token
* @returns {Promise<User>} User information if token is valid
*/
async verifyToken() {
return this.#makeAuthenticatedRequest('/api/auth/verify');
}
/**
* Creates a new user.
* @param {Object} params - Parameters for creating a user.
* @param {string} params.username - The user's username.
* @param {string} params.password - The user's password.
* @param {string} params.role - The user's role, either 'admin' or 'user'.
* @returns {Promise<{ id: string, username: string, role: string, createdAt: string }>} Created user details.
*/
async createUser(params) {
return this.#makeAuthenticatedRequest(`/api/users`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Returns all users. Admin access is required.
* @returns {Promise<Array<{ id: string, username: string, role: string, createdAt: string }>>} List of users.
*/
async getUsers() {
return this.#makeAuthenticatedRequest(`/api/admin/users`);
}
/**
* Gets details of a specific user by ID.
* @param {string} userId - The ID of the user.
* @returns {Promise<{ id: string, username: string, role: string }>} User details.
*/
async getUser(userId) {
return this.#makeAuthenticatedRequest(`/api/users/${userId}`);
}
/**
* Updates details of a user.
* @param {string} userId - The ID of the user.
* @param {Object} params - Update parameters.
* @param {string} [params.username] - The user's new username (optional).
* @param {string} [params.password] - The user's new password (optional).
* @param {string} [params.role] - The user's role, either 'admin' or 'user' (optional).
* @returns {Promise<{ id: string, username: string, role: string, createdAt: string }>} Updated user details.
*/
async updateUser(userId, params) {
return this.#makeAuthenticatedRequest(`/api/users/${userId}`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Deletes a user.
* @param {string} userId - The ID of the user.
* @returns {Promise<string>} Confirmation message.
*/
async deleteUser(userId) {
return this.#makeAuthenticatedRequest(`/api/users/${userId}`, {
method: 'DELETE',
});
}
/**
* Gets all websites that belong to a user.
* @param {string} userId - The ID of the user.
* @param {Object} [params] - Query parameters.
* @param {string} [params.query] - Search text (optional).
* @param {number} [params.page=1] - Page number (optional).
* @param {number} [params.pageSize] - Number of results per page (optional).
* @param {string} [params.orderBy='name'] - Order by column name (optional).
* @returns {Promise<Array<{ id: string, userId: string, domain: string, name: string, shareId: string | null, createdAt: string, updatedAt: string | null, deletedAt: string | null, resetAt: string | null }>>} List of websites belonging to the user.
*/
async getUserWebsites(userId, params = {}) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/users/${userId}/websites?${queryString}`);
}
/**
* Gets all teams that belong to a user.
* @param {string} userId - The ID of the user.
* @param {Object} [params] - Query parameters.
* @param {string} [params.query] - Search text (optional).
* @param {number} [params.page=1] - Page number (optional).
* @param {number} [params.pageSize] - Number of results per page (optional).
* @param {string} [params.orderBy='name'] - Order by column name (optional).
* @returns {Promise<Array<{ id: string, name: string, createdAt: string, updatedAt: string | null, deletedAt: string | null }>>} List of teams belonging to the user.
*/
async getUserTeams(userId, params = {}) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/users/${userId}/teams?${queryString}`);
}
/**
* Creates a new team.
* @param {Object} params - Parameters for creating a team.
* @param {string} params.name - The team's name.
* @returns {Promise<{ accessCode: string, createdAt: string, id: string, name: string, updatedAt: string | null }>} Created team details.
*/
async createTeam(params) {
return this.#makeAuthenticatedRequest(`/api/teams`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Returns all teams.
* @param {Object} params - Query parameters.
* @param {string} [params.query] - Search text (optional).
* @param {number} [params.page=1] - Page number (optional).
* @param {number} [params.pageSize] - Number of results per page (optional).
* @param {string} [params.orderBy='name'] - Order by column name (optional).
* @returns {Promise<Array>} List of all teams with team user information.
*/
async getTeams(params = {}) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/teams?${queryString}`);
}
/**
* Joins a team using an access code.
* @param {Object} params - Parameters for joining a team.
* @param {string} params.accessCode - The team's access code.
* @returns {Promise<Object>} Joined team details.
*/
async joinTeam(params) {
return this.#makeAuthenticatedRequest(`/api/teams/join`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Gets details of a specific team.
* @param {string} teamId - The ID of the team.
* @returns {Promise<Object>} Team details.
*/
async getTeam(teamId) {
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}`);
}
/**
* Updates team details.
* @param {string} teamId - The ID of the team.
* @param {Object} params - Update parameters.
* @param {string} [params.name] - The team's name (optional).
* @param {string} [params.accessCode] - The team's access code (optional).
* @returns {Promise<Object>} Updated team details.
*/
async updateTeam(teamId, params) {
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Deletes a team.
* @param {string} teamId - The ID of the team.
* @returns {Promise<string>} Confirmation message.
*/
async deleteTeam(teamId) {
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}`, {
method: 'DELETE',
});
}
/**
* Gets all users that belong to a team.
* @param {string} teamId - The ID of the team.
* @param {Object} [params] - Query parameters.
* @param {string} [params.query] - Search text (optional).
* @param {number} [params.page=1] - Page number (optional).
* @param {number} [params.pageSize] - Number of results per page (optional).
* @param {string} [params.orderBy='name'] - Order by column name (optional).
* @returns {Promise<Array>} List of team users.
*/
async getTeamUsers(teamId, params = {}) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users?${queryString}`);
}
/**
* Adds a user to a team.
* @param {string} teamId - The ID of the team.
* @param {Object} params - Parameters for adding a user to the team.
* @param {string} params.userId - The user's ID.
* @param {string} params.role - The role to assign (e.g., 'member' or 'view-only').
* @returns {Promise<Object>} Added team user details.
*/
async addUserToTeam(teamId, params) {
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Gets details of a user in a team.
* @param {string} teamId - The ID of the team.
* @param {string} userId - The user's ID.
* @returns {Promise<Object>} Team user details.
*/
async getTeamUser(teamId, userId) {
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users/${userId}`);
}
/**
* Updates a user's role in a team.
* @param {string} teamId - The ID of the team.
* @param {string} userId - The user's ID.
* @param {Object} params - Parameters for updating user role.
* @param {string} params.role - The new role (e.g., 'member' or 'view-only').
* @returns {Promise<string>} Confirmation message.
*/
async updateTeamUserRole(teamId, userId, params) {
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users/${userId}`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Removes a user from a team.
* @param {string} teamId - The ID of the team.
* @param {string} userId - The user's ID.
* @returns {Promise<string>} Confirmation message.
*/
async removeUserFromTeam(teamId, userId) {
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users/${userId}`, {
method: 'DELETE',
});
}
/**
* Returns all tracked websites.
* @param {Object} [params] - Query parameters.
* @param {string} [params.query] - Search text (optional).
* @param {number} [params.page=1] - Page number (optional).
* @param {number} [params.pageSize] - Number of results per page (optional).
* @param {string} [params.orderBy='name'] - Order by column name (optional).
* @returns {Promise<Array<{ id: string, name: string, domain: string, shareId: string | null, resetAt: string | null, createdAt: string, updatedAt: string | null, deletedAt: string | null }>>} List of websites.
*/
async getWebsites(params = {}) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites?${queryString}`);
}
/**
* Creates a new website.
* @param {Object} params - Website parameters.
* @param {string} params.domain - The full domain of the tracked website.
* @param {string} params.name - The name of the website in Umami.
* @param {string} [params.shareId] - A unique string to enable a share URL (optional).
* @param {string} [params.teamId] - The ID of the team the website will be created under (optional).
* @returns {Promise<{ id: number, websiteUuid: string, websiteId: number, name: string, domain: string, shareId: string | null, createdAt: string }>} Details of the created website.
*/
async createWebsite(params) {
return this.#makeAuthenticatedRequest(`/api/websites`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Gets details of a specific website by ID.
* @param {string} websiteId - The ID of the website.
* @returns {Promise<{ id: string, name: string, domain: string, shareId: string | null, resetAt: string | null, userId: string, createdAt: string, updatedAt: string | null, deletedAt: string | null }>} Website details.
*/
async getWebsite(websiteId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`);
}
/**
* Updates details of a website.
* @param {string} websiteId - The ID of the website.
* @param {Object} params - Update parameters.
* @param {string} [params.name] - The name of the website in Umami (optional).
* @param {string} [params.domain] - The full domain of the tracked website (optional).
* @param {string} [params.shareId] - A unique string to enable a share URL or null to unshare (optional).
* @returns {Promise<{ id: string, name: string, domain: string, shareId: string | null, resetAt: string | null, userId: string, createdAt: string, updatedAt: string | null, deletedAt: string | null }>} Updated website details.
*/
async updateWebsite(websiteId, params) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Deletes a website.
* @param {string} websiteId - The ID of the website.
* @returns {Promise<string>} Confirmation message.
*/
async deleteWebsite(websiteId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`, {
method: 'DELETE',
});
}
/**
* Resets a website by removing all data related to it.
* @param {string} websiteId - The ID of the website.
* @returns {Promise<string>} Confirmation message.
*/
async resetWebsite(websiteId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/reset`, {
method: 'POST',
});
}
/**
* Gets all websites that belong to a team.
* @param {string} teamId - The ID of the team.
* @param {Object} [params] - Query parameters.
* @param {string} [params.query] - Search text (optional).
* @param {number} [params.page=1] - Page number (optional).
* @param {number} [params.pageSize] - Number of results per page (optional).
* @param {string} [params.orderBy='name'] - Order by column name (optional).
* @returns {Promise<Array>} List of team websites.
*/
async getTeamWebsites(teamId, params = {}) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/websites?${queryString}`);
}
/**
* Gets website session details within a given time range
* @param {string} websiteId - Website ID
* @param {Object} params - Query parameters
* @param {number} params.startAt - Timestamp (in ms) of starting date
* @param {number} params.endAt - Timestamp (in ms) of end date
* @param {string} [params.query] - Search text
* @param {number} [params.page=1] - Page number
* @param {number} [params.pageSize] - Results per page
* @param {string} [params.orderBy] - Order by column name
* @returns {Promise<{ data: Session[], count: number, page: number, pageSize: number }>}
*/
async getSessions(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions?${queryString}`);
}
/**
* Gets summarized website session statistics
* @param {string} websiteId - Website ID
* @param {Object} params - Query parameters
* @param {number} params.startAt - Timestamp (in ms) of starting date
* @param {number} params.endAt - Timestamp (in ms) of end date
* @param {string} [params.url] - Filter by URL
* @param {string} [params.referrer] - Filter by referrer
* @param {string} [params.title] - Filter by page title
* @param {string} [params.query] - Filter by query
* @param {string} [params.event] - Filter by event name
* @param {string} [params.host] - Filter by hostname
* @param {string} [params.os] - Filter by operating system
* @param {string} [params.browser] - Filter by browser
* @param {string} [params.device] - Filter by device
* @param {string} [params.country] - Filter by country
* @param {string} [params.region] - Filter by region
* @param {string} [params.city] - Filter by city
* @returns {Promise<SessionStats>}
*/
async getSessionStats(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions/stats?${queryString}`);
}
/**
* Gets session details for an individual session
* @param {string} websiteId - Website ID
* @param {string} sessionId - Session ID
* @returns {Promise<Session>}
*/
async getSession(websiteId, sessionId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions/${sessionId}`);
}
/**
* Gets session activity for an individual session
* @param {string} websiteId - Website ID
* @param {string} sessionId - Session ID
* @param {Object} params - Query parameters
* @param {number} params.startAt - Timestamp (in ms) of starting date
* @param {number} params.endAt - Timestamp (in ms) of end date
* @returns {Promise<SessionActivity[]>}
*/
async getSessionActivity(websiteId, sessionId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions/${sessionId}/activity?${queryString}`);
}
/**
* Gets session properties for an individual session
* @param {string} websiteId - Website ID
* @param {string} sessionId - Session ID
* @returns {Promise<SessionProperty[]>}
*/
async getSessionProperties(websiteId, sessionId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions/${sessionId}/properties`);
}
/**
* Gets session data counts by property name
* @param {string} websiteId - Website ID
* @param {Object} params - Query parameters
* @param {number} params.startAt - Timestamp (in ms) of starting date
* @param {number} params.endAt - Timestamp (in ms) of end date
* @returns {Promise<PropertyCount[]>}
*/
async getSessionDataProperties(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/session-data/properties?${queryString}`);
}
/**
* Gets session data counts for a given property
* @param {string} websiteId - Website ID
* @param {Object} params - Query parameters
* @param {number} params.startAt - Timestamp (in ms) of starting date
* @param {number} params.endAt - Timestamp (in ms) of end date
* @param {string} params.propertyName - Property name
* @returns {Promise<PropertyValue[]>}
*/
async getSessionDataValues(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/session-data/values?${queryString}`);
}
/**
* Gets all tracked websites
* @param {Object} [params] - Query parameters
* @param {string} [params.query] - Search text
* @param {number} [params.page=1] - Page number
* @param {number} [params.pageSize] - Results per page
* @param {string} [params.orderBy='name'] - Order by column name
* @returns {Promise<Array>} List of websites
*/
async getWebsites(params = {}) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites?${queryString}`);
}
/**
* Creates a new website
* @param {Object} params - Website parameters
* @param {string} params.domain - The full domain of the tracked website
* @param {string} params.name - The name of the website in Umami
* @param {string} [params.shareId] - A unique string to enable a share url
* @param {string} [params.teamId] - The ID of the team the website will be created under
* @returns {Promise<Object>} Created website details
*/
async createWebsite(params) {
return this.#makeAuthenticatedRequest('/api/websites', {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Gets a website by ID
* @param {string} websiteId - Website ID
* @returns {Promise<Object>} Website details
*/
async getWebsite(websiteId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`);
}
/**
* Updates a website
* @param {string} websiteId - Website ID
* @param {Object} params - Update parameters
* @param {string} [params.name] - The name of the website in Umami
* @param {string} [params.domain] - The full domain of the tracked website
* @param {string} [params.shareId] - A unique string to enable a share url
* @returns {Promise<Object>} Updated website details
*/
async updateWebsite(websiteId, params) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`, {
method: 'POST',
body: JSON.stringify(params),
});
}
/**
* Deletes a website
* @param {string} websiteId - Website ID
* @returns {Promise<string>} Confirmation message
*/
async deleteWebsite(websiteId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`, {
method: 'DELETE',
});
}
/**
* Resets a website by removing all data
* @param {string} websiteId - Website ID
* @returns {Promise<string>} Confirmation message
*/
async resetWebsite(websiteId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/reset`, {
method: 'POST',
});
}
/**
* Gets the number of active users on a website
* @param {string} websiteId - Website ID
* @returns {Promise<Object>} Active users count
*/
async getActiveUsers(websiteId) {
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/active`);
}
/**
* Gets events within a given time range
* @param {string} websiteId - Website ID
* @param {Object} params - Query parameters
* @param {number} params.startAt - Timestamp (in ms) of starting date
* @param {number} params.endAt - Timestamp (in ms) of end date
* @param {string} params.unit - Time unit (year | month | hour | day)
* @param {string} params.timezone - Timezone (ex. America/Los_Angeles)
* @param {string} [params.url] - Filter by URL
* @param {string} [params.referrer] - Filter by referrer
* @param {string} [params.title] - Filter by page title
* @param {string} [params.host] - Filter by hostname
* @param {string} [params.os] - Filter by operating system
* @param {string} [params.browser] - Filter by browser
* @param {string} [params.device] - Filter by device
* @param {string} [params.country] - Filter by country
* @param {string} [params.region] - Filter by region
* @param {string} [params.city] - Filter by city
* @returns {Promise<Array>} Event series data
*/
async getEventsSeries(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/events/series?${queryString}`);
}
/**
* Gets website event details within a given time range.
* @param {string} websiteId - The ID of the website.
* @param {Object} params - Query parameters.
* @param {number} params.startAt - Timestamp (in ms) of the starting date.
* @param {number} params.endAt - Timestamp (in ms) of the end date.
* @param {string} [params.query] - Search text (optional).
* @param {number} [params.page=1] - Page number (optional).
* @param {number} [params.pageSize] - Number of results to return (optional).
* @param {string} [params.orderBy] - Order by column name (optional).
* @returns {Promise<{ data: Array, count: number, page: number, pageSize: number }>} Event data response.
*/
async getWebsiteEvents(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/events?${queryString}`);
}
/**
* Gets summarized website statistics.
* @param {string} websiteId - The ID of the website.
* @param {Object} params - Query parameters.
* @param {number} params.startAt - Timestamp (in ms) of starting date.
* @param {number} params.endAt - Timestamp (in ms) of end date.
* @param {string} [params.url] - Filter by URL (optional).
* @param {string} [params.referrer] - Filter by referrer (optional).
* @param {string} [params.title] - Filter by page title (optional).
* @param {string} [params.query] - Filter by query (optional).
* @param {string} [params.event] - Filter by event name (optional).
* @param {string} [params.host] - Filter by hostname (optional).
* @param {string} [params.os] - Filter by operating system (optional).
* @param {string} [params.browser] - Filter by browser (optional).
* @param {string} [params.device] - Filter by device (e.g., Mobile, optional).
* @param {string} [params.country] - Filter by country (optional).
* @param {string} [params.region] - Filter by region/state/province (optional).
* @param {string} [params.city] - Filter by city (optional).
* @returns {Promise<{ pageviews: { value: number, prev: number }, visitors: { value: number, prev: number }, visits: { value: number, prev: number }, bounces: { value: number, prev: number }, totaltime: { value: number, prev: number } }>} Summarized website statistics.
*/
async getWebsiteStats(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/stats?${queryString}`);
}
/**
* Gets event data names, properties, and counts.
* @param {string} websiteId - The ID of the website.
* @param {Object} params - Query parameters.
* @param {number} params.startAt - Timestamp (in ms) of the starting date.
* @param {number} params.endAt - Timestamp (in ms) of the end date.
* @param {string} [params.event] - Event name filter (optional).
* @returns {Promise<Array<{ eventName: string, propertyName: string, dataType: number, total: number }>>} Event data summary.
*/
async getEventDataEvents(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/event-data/events?${queryString}`);
}
/**
* Gets event data property and value counts within a given time range.
* @param {string} websiteId - The ID of the website.
* @param {Object} params - Query parameters.
* @param {number} params.startAt - Timestamp (in ms) of the starting date.
* @param {number} params.endAt - Timestamp (in ms) of the end date.
* @returns {Promise<Array<{ propertyName: string, dataType: number, value: string, total: number }>>} Event data fields.
*/
async getEventDataFields(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/event-data/fields?${queryString}`);
}
/**
* Gets event data counts for a given event and property.
* @param {string} websiteId - The ID of the website.
* @param {Object} params - Query parameters.
* @param {number} params.startAt - Timestamp (in ms) of the starting date.
* @param {number} params.endAt - Timestamp (in ms) of the end date.
* @param {string} params.eventName - The name of the event.
* @param {string} params.propertyName - The property name.
* @returns {Promise<Array<{ value: string, total: number }>>} Event data values.
*/
async getEventDataValues(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/event-data/values?${queryString}`);
}
/**
* Gets summarized website events, fields, and records within a given time range.
* @param {string} websiteId - The ID of the website.
* @param {Object} params - Query parameters.
* @param {number} params.startAt - Timestamp (in ms) of the starting date.
* @param {number} params.endAt - Timestamp (in ms) of the end date.
* @returns {Promise<Array<{ events: number, fields: number, records: number }>>} Summary of events, fields, and records.
*/
async getEventDataStats(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/event-data/stats?${queryString}`);
}
/**
* Gets pageviews within a given time range
* @param {string} websiteId - Website ID
* @param {Object} params - Query parameters
* @param {number} params.startAt - Timestamp (in ms) of starting date
* @param {number} params.endAt - Timestamp (in ms) of end date
* @param {string} params.unit - Time unit (year | month | hour | day)
* @param {string} params.timezone - Timezone (ex. America/Los_Angeles)
* @param {string} [params.url] - Filter by URL
* @param {string} [params.referrer] - Filter by referrer
* @param {string} [params.title] - Filter by page title
* @param {string} [params.host] - Filter by hostname
* @param {string} [params.os] - Filter by operating system
* @param {string} [params.browser] - Filter by browser
* @param {string} [params.device] - Filter by device
* @param {string} [params.country] - Filter by country
* @param {string} [params.region] - Filter by region
* @param {string} [params.city] - Filter by city
* @returns {Promise<Object>} Pageview data
*/
async getPageviews(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/pageviews?${queryString}`);
}
/**
* Gets metrics for a given time range
* @param {string} websiteId - Website ID
* @param {Object} params - Query parameters
* @param {number} params.startAt - Timestamp (in ms) of starting date
* @param {number} params.endAt - Timestamp (in ms) of end date
* @param {string} params.type - Metrics type (url | referrer | browser | os | device | country | event)
* @param {string} [params.url] - Filter by URL
* @param {string} [params.referrer] - Filter by referrer
* @param {string} [params.title] - Filter by page title
* @param {string} [params.query] - Filter by query
* @param {string} [params.host] - Filter by hostname
* @param {string} [params.os] - Filter by operating system
* @param {string} [params.browser] - Filter by browser
* @param {string} [params.device] - Filter by device
* @param {string} [params.country] - Filter by country
* @param {string} [params.region] - Filter by region
* @param {string} [params.city] - Filter by city
* @param {string} [params.language] - Filter by language
* @param {string} [params.event] - Filter by event
* @param {number} [params.limit=500] - Number of events returned
* @returns {Promise<Array>} Metrics data
*/
async getMetrics(websiteId, params) {
const queryString = this.#formatQueryParams(params);
return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/metrics?${queryString}`);
}
/**
* Sends an event to Umami
* @param {EventPayload} payload - Event data
* @returns {Promise<void>}
*/
async sendEvent(payload) {
// No authentication needed for /api/send
const response = await fetch(`${this.baseUrl}/api/send`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': navigator.userAgent, // Required for event registration
},
body: JSON.stringify({
payload: {
hostname: payload.hostname || window.location.hostname,
language: payload.language || navigator.language,
referrer: payload.referrer || document.referrer,
screen: payload.screen || `${window.screen.width}x${window.screen.height}`,
title: payload.title || document.title,
url: payload.url || window.location.pathname,
website: payload.website,
name: payload.name,
data: payload.data,
},
type: 'event',
}),
});
if (!response.ok) {
throw new Error(`Failed to send event: ${response.statusText}`);
}
}
}
export default UmamiClient;