mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
Compare commits
1 Commits
main
...
waleedlati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83f3be846c |
@@ -3600,6 +3600,25 @@ export const ResendIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const GoogleAnalyticsIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'>
|
||||
<g transform='translate(-174.95 -339.18)scale(3.54856)'>
|
||||
<path
|
||||
d='M149.3 112.8V221c0 12.1 8.4 18.9 17.2 18.9 8.2 0 17.2-5.7 17.2-18.9V113.6c0-11.1-8.2-18-17.2-18s-17.2 7.6-17.2 17.2'
|
||||
fill='#f8ab00'
|
||||
/>
|
||||
<path
|
||||
d='M104.2 167.7V221c0 12.1 8.4 18.9 17.2 18.9 8.2 0 17.2-5.7 17.2-18.9v-52.5c0-11.1-8.2-18-17.2-18s-17.2 7.7-17.2 17.2'
|
||||
fill='#e37300'
|
||||
/>
|
||||
<path
|
||||
d='M93.6 222.7c0 9.5-7.7 17.2-17.2 17.2s-17.2-7.7-17.2-17.2 7.7-17.2 17.2-17.2 17.2 7.6 17.2 17.2'
|
||||
fill='#e37300'
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const GoogleAdsIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>
|
||||
<g transform='matrix(.257748 0 0 .257745 -.361416 2.515516)'>
|
||||
|
||||
@@ -47,11 +47,12 @@ import {
|
||||
FirecrawlIcon,
|
||||
FirefliesIcon,
|
||||
GammaIcon,
|
||||
GithubIcon,
|
||||
GitLabIcon,
|
||||
GithubIcon,
|
||||
GmailIcon,
|
||||
GongIcon,
|
||||
GoogleAdsIcon,
|
||||
GoogleAnalyticsIcon,
|
||||
GoogleBigQueryIcon,
|
||||
GoogleBooksIcon,
|
||||
GoogleCalendarIcon,
|
||||
@@ -91,9 +92,9 @@ import {
|
||||
LinkupIcon,
|
||||
LoopsIcon,
|
||||
LumaIcon,
|
||||
MailServerIcon,
|
||||
MailchimpIcon,
|
||||
MailgunIcon,
|
||||
MailServerIcon,
|
||||
Mem0Icon,
|
||||
MicrosoftDataverseIcon,
|
||||
MicrosoftExcelIcon,
|
||||
@@ -128,6 +129,8 @@ import {
|
||||
ResendIcon,
|
||||
RevenueCatIcon,
|
||||
S3Icon,
|
||||
SQSIcon,
|
||||
STTIcon,
|
||||
SalesforceIcon,
|
||||
SearchIcon,
|
||||
SendgridIcon,
|
||||
@@ -139,19 +142,17 @@ import {
|
||||
SimilarwebIcon,
|
||||
SlackIcon,
|
||||
SmtpIcon,
|
||||
SQSIcon,
|
||||
SshIcon,
|
||||
STTIcon,
|
||||
StagehandIcon,
|
||||
StripeIcon,
|
||||
SupabaseIcon,
|
||||
TTSIcon,
|
||||
TavilyIcon,
|
||||
TelegramIcon,
|
||||
TextractIcon,
|
||||
TinybirdIcon,
|
||||
TranslateIcon,
|
||||
TrelloIcon,
|
||||
TTSIcon,
|
||||
TwilioIcon,
|
||||
TypeformIcon,
|
||||
UpstashIcon,
|
||||
@@ -162,11 +163,11 @@ import {
|
||||
WhatsAppIcon,
|
||||
WikipediaIcon,
|
||||
WordpressIcon,
|
||||
xIcon,
|
||||
YouTubeIcon,
|
||||
ZendeskIcon,
|
||||
ZepIcon,
|
||||
ZoomIcon,
|
||||
xIcon,
|
||||
} from '@/components/icons'
|
||||
|
||||
type IconComponent = ComponentType<SVGProps<SVGSVGElement>>
|
||||
@@ -218,6 +219,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
gmail_v2: GmailIcon,
|
||||
gong: GongIcon,
|
||||
google_ads: GoogleAdsIcon,
|
||||
google_analytics: GoogleAnalyticsIcon,
|
||||
google_bigquery: GoogleBigQueryIcon,
|
||||
google_books: GoogleBooksIcon,
|
||||
google_calendar_v2: GoogleCalendarIcon,
|
||||
|
||||
@@ -53,6 +53,9 @@ Extract structured content from web pages with comprehensive metadata support. C
|
||||
| `url` | string | Yes | The URL to scrape content from \(e.g., "https://example.com/page"\) |
|
||||
| `scrapeOptions` | json | No | Options for content scraping |
|
||||
| `apiKey` | string | Yes | Firecrawl API key |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -86,6 +89,9 @@ Search for information on the web using Firecrawl
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `query` | string | Yes | The search query to use |
|
||||
| `apiKey` | string | Yes | Firecrawl API key |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -123,6 +129,9 @@ Crawl entire websites and extract structured content from all accessible pages
|
||||
| `includePaths` | json | No | URL paths to include in crawling \(e.g., \["/docs/*", "/api/*"\]\). Only these paths will be crawled |
|
||||
| `onlyMainContent` | boolean | No | Extract only main content from pages |
|
||||
| `apiKey` | string | Yes | Firecrawl API Key |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -142,7 +151,6 @@ Crawl entire websites and extract structured content from all accessible pages
|
||||
| ↳ `statusCode` | number | HTTP status code |
|
||||
| ↳ `ogLocaleAlternate` | array | Alternate locale versions |
|
||||
| `total` | number | Total number of pages found during crawl |
|
||||
| `creditsUsed` | number | Number of credits consumed by the crawl operation |
|
||||
|
||||
### `firecrawl_map`
|
||||
|
||||
@@ -161,6 +169,9 @@ Get a complete list of URLs from any website quickly and reliably. Useful for di
|
||||
| `timeout` | number | No | Request timeout in milliseconds |
|
||||
| `location` | json | No | Geographic context for proxying \(country, languages\) |
|
||||
| `apiKey` | string | Yes | Firecrawl API key |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -187,6 +198,9 @@ Extract structured data from entire webpages using natural language prompts and
|
||||
| `ignoreInvalidURLs` | boolean | No | Skip invalid URLs in the array \(default: true\) |
|
||||
| `scrapeOptions` | json | No | Advanced scraping configuration options |
|
||||
| `apiKey` | string | Yes | Firecrawl API key |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -217,7 +231,6 @@ Autonomous web data extraction agent. Searches and gathers information based on
|
||||
| `success` | boolean | Whether the agent operation was successful |
|
||||
| `status` | string | Current status of the agent job \(processing, completed, failed\) |
|
||||
| `data` | object | Extracted data from the agent |
|
||||
| `creditsUsed` | number | Number of credits consumed by this agent task |
|
||||
| `expiresAt` | string | Timestamp when the results expire \(24 hours\) |
|
||||
| `sources` | object | Array of source URLs used by the agent |
|
||||
|
||||
|
||||
129
apps/docs/content/docs/en/tools/google_analytics.mdx
Normal file
129
apps/docs/content/docs/en/tools/google_analytics.mdx
Normal file
@@ -0,0 +1,129 @@
|
||||
---
|
||||
title: Google Analytics
|
||||
description: Query GA4 analytics data and reports
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
|
||||
<BlockInfoCard
|
||||
type="google_analytics"
|
||||
color="#E0E0E0"
|
||||
/>
|
||||
|
||||
{/* MANUAL-CONTENT-START:intro */}
|
||||
[Google Analytics](https://analytics.google.com) is Google's web and app analytics platform. Through Sim, your agents can query GA4 property data to automate reporting, monitoring, and analysis workflows.
|
||||
|
||||
**The following Google Analytics Data API operations are included in this integration:**
|
||||
|
||||
- **Run Report:** Generate customized reports with dimensions, metrics, date ranges, filters, and sorting. Supports pagination for large datasets.
|
||||
- **Run Realtime Report:** Get live data from the last 30 minutes, including active users, page views, and conversions in real time.
|
||||
- **Get Metadata:** Discover all available dimensions and metrics for a GA4 property, including their descriptions and categories.
|
||||
|
||||
With these operations, your Sim agents can automate daily/weekly analytics reporting, monitor real-time traffic and conversions, build dashboards from GA4 data, detect anomalies in key metrics, and enrich workflows with analytics context—all without manual work in the Google Analytics UI.
|
||||
{/* MANUAL-CONTENT-END */}
|
||||
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate Google Analytics GA4 into your workflow. Run custom reports, get realtime data, and discover available dimensions and metrics.
|
||||
|
||||
|
||||
|
||||
## Tools
|
||||
|
||||
### `google_analytics_run_report`
|
||||
|
||||
Run a customized report on Google Analytics GA4 property data
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `propertyId` | string | Yes | The GA4 property ID \(e.g., 123456789\) |
|
||||
| `dimensions` | string | Yes | Comma-separated dimension names \(e.g., date,country,deviceCategory\). See GA4 dimensions reference. |
|
||||
| `metrics` | string | Yes | Comma-separated metric names \(e.g., activeUsers,sessions,screenPageViews\). See GA4 metrics reference. |
|
||||
| `startDate` | string | Yes | Start date in YYYY-MM-DD format, or relative dates like "7daysAgo", "30daysAgo", "yesterday" |
|
||||
| `endDate` | string | Yes | End date in YYYY-MM-DD format, or "today", "yesterday" |
|
||||
| `dimensionFilter` | string | No | Dimension filter as JSON \(e.g., \{"filter":\{"fieldName":"country","stringFilter":\{"value":"US"\}\}\}\) |
|
||||
| `metricFilter` | string | No | Metric filter as JSON \(e.g., \{"filter":\{"fieldName":"activeUsers","numericFilter":\{"operation":"GREATER_THAN","value":\{"int64Value":"100"\}\}\}\}\) |
|
||||
| `orderBys` | string | No | Order by specification as JSON array \(e.g., \[\{"metric":\{"metricName":"activeUsers"\},"desc":true\}\]\) |
|
||||
| `limit` | number | No | Maximum number of rows to return \(default: 10000, max: 250000\) |
|
||||
| `offset` | number | No | Starting row offset for pagination \(default: 0\) |
|
||||
| `keepEmptyRows` | boolean | No | Whether to include rows with all zero metric values |
|
||||
| `currencyCode` | string | No | Currency code for revenue metrics \(e.g., USD, EUR\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `dimensionHeaders` | array | Dimension column headers |
|
||||
| ↳ `name` | string | Dimension name |
|
||||
| `metricHeaders` | array | Metric column headers |
|
||||
| ↳ `name` | string | Metric name |
|
||||
| ↳ `type` | string | Metric data type |
|
||||
| `rows` | array | Report data rows |
|
||||
| ↳ `dimensionValues` | json | Array of dimension values for this row |
|
||||
| ↳ `metricValues` | json | Array of metric values for this row |
|
||||
| `rowCount` | number | Total number of rows in the result |
|
||||
| `metadata` | json | Report metadata including currency code and time zone |
|
||||
| ↳ `currencyCode` | string | Currency code used in the report |
|
||||
| ↳ `timeZone` | string | Time zone used in the report |
|
||||
|
||||
### `google_analytics_run_realtime_report`
|
||||
|
||||
Run a realtime report on Google Analytics GA4 property data from the last 30 minutes
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `propertyId` | string | Yes | The GA4 property ID \(e.g., 123456789\) |
|
||||
| `dimensions` | string | No | Comma-separated dimension names for realtime data \(e.g., unifiedScreenName,country,deviceCategory\) |
|
||||
| `metrics` | string | Yes | Comma-separated metric names \(e.g., activeUsers,screenPageViews,conversions\) |
|
||||
| `dimensionFilter` | string | No | Dimension filter as JSON |
|
||||
| `metricFilter` | string | No | Metric filter as JSON |
|
||||
| `limit` | number | No | Maximum number of rows to return \(default: 10000, max: 250000\) |
|
||||
| `startMinutesAgo` | number | No | Start of the time window in minutes ago \(default: 29, max: 29 for standard, 59 for 360\) |
|
||||
| `endMinutesAgo` | number | No | End of the time window in minutes ago \(default: 0, meaning now\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `dimensionHeaders` | array | Dimension column headers |
|
||||
| ↳ `name` | string | Dimension name |
|
||||
| `metricHeaders` | array | Metric column headers |
|
||||
| ↳ `name` | string | Metric name |
|
||||
| ↳ `type` | string | Metric data type |
|
||||
| `rows` | array | Realtime report data rows |
|
||||
| ↳ `dimensionValues` | json | Array of dimension values for this row |
|
||||
| ↳ `metricValues` | json | Array of metric values for this row |
|
||||
| `rowCount` | number | Total number of rows in the result |
|
||||
|
||||
### `google_analytics_get_metadata`
|
||||
|
||||
Get available dimensions, metrics, and their descriptions for a Google Analytics GA4 property
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `propertyId` | string | Yes | The GA4 property ID \(e.g., 123456789\). Use 0 to get universal metadata available across all properties. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `dimensions` | array | Available dimensions for the property |
|
||||
| ↳ `apiName` | string | API name to use in report requests |
|
||||
| ↳ `uiName` | string | Human-readable display name |
|
||||
| ↳ `description` | string | Description of the dimension |
|
||||
| ↳ `category` | string | Category grouping |
|
||||
| `metrics` | array | Available metrics for the property |
|
||||
| ↳ `apiName` | string | API name to use in report requests |
|
||||
| ↳ `uiName` | string | Human-readable display name |
|
||||
| ↳ `description` | string | Description of the metric |
|
||||
| ↳ `category` | string | Category grouping |
|
||||
| ↳ `type` | string | Data type of the metric |
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ Search for books using the Google Books API
|
||||
| `startIndex` | number | No | Index of the first result to return \(for pagination\) |
|
||||
| `maxResults` | number | No | Maximum number of results to return \(1-40\) |
|
||||
| `langRestrict` | string | No | Restrict results to a specific language \(ISO 639-1 code\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -82,6 +84,8 @@ Get detailed information about a specific book volume
|
||||
| `apiKey` | string | Yes | Google Books API key |
|
||||
| `volumeId` | string | Yes | The ID of the volume to retrieve |
|
||||
| `projection` | string | No | Projection level \(full, lite\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ Get current air quality data for a location
|
||||
| `lat` | number | Yes | Latitude coordinate |
|
||||
| `lng` | number | Yes | Longitude coordinate |
|
||||
| `languageCode` | string | No | Language code for the response \(e.g., "en", "es"\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -91,6 +93,8 @@ Get directions and route information between two locations
|
||||
| `waypoints` | json | No | Array of intermediate waypoints |
|
||||
| `units` | string | No | Unit system: metric or imperial |
|
||||
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -135,6 +139,8 @@ Calculate travel distance and time between multiple origins and destinations
|
||||
| `avoid` | string | No | Features to avoid: tolls, highways, or ferries |
|
||||
| `units` | string | No | Unit system: metric or imperial |
|
||||
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -163,6 +169,8 @@ Get elevation data for a location
|
||||
| `apiKey` | string | Yes | Google Maps API key |
|
||||
| `lat` | number | Yes | Latitude coordinate |
|
||||
| `lng` | number | Yes | Longitude coordinate |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -185,6 +193,8 @@ Convert an address into geographic coordinates (latitude and longitude)
|
||||
| `address` | string | Yes | The address to geocode |
|
||||
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
|
||||
| `region` | string | No | Region bias as a ccTLD code \(e.g., us, uk\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -217,6 +227,8 @@ Geolocate a device using WiFi access points, cell towers, or IP address
|
||||
| `considerIp` | boolean | No | Whether to use IP address for geolocation \(default: true\) |
|
||||
| `cellTowers` | array | No | Array of cell tower objects with cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode |
|
||||
| `wifiAccessPoints` | array | No | Array of WiFi access point objects with macAddress \(required\), signalStrength, etc. |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -238,6 +250,8 @@ Get detailed information about a specific place
|
||||
| `placeId` | string | Yes | Google Place ID |
|
||||
| `fields` | string | No | Comma-separated list of fields to return |
|
||||
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -290,6 +304,8 @@ Search for places using a text query
|
||||
| `type` | string | No | Place type filter \(e.g., restaurant, cafe, hotel\) |
|
||||
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
|
||||
| `region` | string | No | Region bias as a ccTLD code \(e.g., us, uk\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -322,6 +338,8 @@ Convert geographic coordinates (latitude and longitude) into a human-readable ad
|
||||
| `lat` | number | Yes | Latitude coordinate |
|
||||
| `lng` | number | Yes | Longitude coordinate |
|
||||
| `language` | string | No | Language code for results \(e.g., en, es, fr\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -346,6 +364,8 @@ Snap GPS coordinates to the nearest road segment
|
||||
| `apiKey` | string | Yes | Google Maps API key with Roads API enabled |
|
||||
| `path` | string | Yes | Pipe-separated list of lat,lng coordinates \(e.g., "60.170880,24.942795\|60.170879,24.942796"\) |
|
||||
| `interpolate` | boolean | No | Whether to interpolate additional points along the road |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -399,6 +419,8 @@ Get timezone information for a location
|
||||
| `lng` | number | Yes | Longitude coordinate |
|
||||
| `timestamp` | number | No | Unix timestamp to determine DST offset \(defaults to current time\) |
|
||||
| `language` | string | No | Language code for timezone name \(e.g., en, es, fr\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -424,6 +446,8 @@ Validate and standardize a postal address
|
||||
| `regionCode` | string | No | ISO 3166-1 alpha-2 country code \(e.g., "US", "CA"\) |
|
||||
| `locality` | string | No | City or locality name |
|
||||
| `enableUspsCass` | boolean | No | Enable USPS CASS validation for US addresses |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ Analyze a webpage for performance, accessibility, SEO, and best practices using
|
||||
| `category` | string | No | Lighthouse categories to analyze \(comma-separated\): performance, accessibility, best-practices, seo |
|
||||
| `strategy` | string | No | Analysis strategy: desktop or mobile |
|
||||
| `locale` | string | No | Locale for results \(e.g., en, fr, de\) |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ Translate text between languages using the Google Cloud Translation API. Support
|
||||
| `target` | string | Yes | Target language code \(e.g., "es", "fr", "de", "ja"\) |
|
||||
| `source` | string | No | Source language code. If omitted, the API will auto-detect the source language. |
|
||||
| `format` | string | No | Format of the text: "text" for plain text, "html" for HTML content |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -61,6 +64,9 @@ Detect the language of text using the Google Cloud Translation API.
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Google Cloud API key with Cloud Translation API enabled |
|
||||
| `text` | string | Yes | The text to detect the language of |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -138,6 +138,26 @@ Get the full transcript of a recording
|
||||
| ↳ `end` | number | End timestamp in ms |
|
||||
| ↳ `text` | string | Transcript text |
|
||||
|
||||
### `grain_list_views`
|
||||
|
||||
List available Grain views for webhook subscriptions
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Grain API key \(Personal Access Token\) |
|
||||
| `typeFilter` | string | No | Optional view type filter: recordings, highlights, or stories |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `views` | array | Array of Grain views |
|
||||
| ↳ `id` | string | View UUID |
|
||||
| ↳ `name` | string | View name |
|
||||
| ↳ `type` | string | View type: recordings, highlights, or stories |
|
||||
|
||||
### `grain_list_teams`
|
||||
|
||||
List all teams in the workspace
|
||||
@@ -185,15 +205,9 @@ Create a webhook to receive recording events
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | Grain API key \(Personal Access Token\) |
|
||||
| `hookUrl` | string | Yes | Webhook endpoint URL \(e.g., "https://example.com/webhooks/grain"\) |
|
||||
| `hookType` | string | Yes | Type of webhook: "recording_added" or "upload_status" |
|
||||
| `filterBeforeDatetime` | string | No | Filter: recordings before this ISO8601 date \(e.g., "2024-01-15T00:00:00Z"\) |
|
||||
| `filterAfterDatetime` | string | No | Filter: recordings after this ISO8601 date \(e.g., "2024-01-01T00:00:00Z"\) |
|
||||
| `filterParticipantScope` | string | No | Filter: "internal" or "external" |
|
||||
| `filterTeamId` | string | No | Filter: specific team UUID \(e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890"\) |
|
||||
| `filterMeetingTypeId` | string | No | Filter: specific meeting type UUID \(e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890"\) |
|
||||
| `includeHighlights` | boolean | No | Include highlights in webhook payload |
|
||||
| `includeParticipants` | boolean | No | Include participants in webhook payload |
|
||||
| `includeAiSummary` | boolean | No | Include AI summary in webhook payload |
|
||||
| `viewId` | string | Yes | Grain view ID from GET /_/public-api/views |
|
||||
| `actions` | array | No | Optional list of actions to subscribe to: added, updated, removed |
|
||||
| `items` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -202,9 +216,8 @@ Create a webhook to receive recording events
|
||||
| `id` | string | Hook UUID |
|
||||
| `enabled` | boolean | Whether hook is active |
|
||||
| `hook_url` | string | The webhook URL |
|
||||
| `hook_type` | string | Type of hook: recording_added or upload_status |
|
||||
| `filter` | object | Applied filters |
|
||||
| `include` | object | Included fields |
|
||||
| `view_id` | string | Grain view ID for the webhook |
|
||||
| `actions` | array | Configured actions for the webhook |
|
||||
| `inserted_at` | string | ISO8601 creation timestamp |
|
||||
|
||||
### `grain_list_hooks`
|
||||
@@ -225,9 +238,8 @@ List all webhooks for the account
|
||||
| ↳ `id` | string | Hook UUID |
|
||||
| ↳ `enabled` | boolean | Whether hook is active |
|
||||
| ↳ `hook_url` | string | Webhook URL |
|
||||
| ↳ `hook_type` | string | Type: recording_added or upload_status |
|
||||
| ↳ `filter` | object | Applied filters |
|
||||
| ↳ `include` | object | Included fields |
|
||||
| ↳ `view_id` | string | Grain view ID |
|
||||
| ↳ `actions` | array | Configured actions |
|
||||
| ↳ `inserted_at` | string | Creation timestamp |
|
||||
|
||||
### `grain_delete_hook`
|
||||
|
||||
@@ -64,6 +64,7 @@ Extract and process web content into clean, LLM-friendly text using Jina AI Read
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `content` | string | The extracted content from the URL, processed into clean, LLM-friendly text |
|
||||
| `tokensUsed` | number | Number of Jina tokens consumed by this request |
|
||||
|
||||
### `jina_search`
|
||||
|
||||
@@ -97,5 +98,6 @@ Search the web and return top 5 results with LLM-friendly content. Each result i
|
||||
| ↳ `content` | string | LLM-friendly extracted content |
|
||||
| ↳ `usage` | object | Token usage information |
|
||||
| ↳ `tokens` | number | Number of tokens consumed by this request |
|
||||
| `tokensUsed` | number | Number of Jina tokens consumed by this request |
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ Search the web for information using Linkup
|
||||
| `includeDomains` | string | No | Comma-separated list of domain names to restrict search results to |
|
||||
| `includeInlineCitations` | boolean | No | Add inline citations to answers \(only applies when outputType is "sourcedAnswer"\) |
|
||||
| `includeSources` | boolean | No | Include sources in response |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
"gmail",
|
||||
"gong",
|
||||
"google_ads",
|
||||
"google_analytics",
|
||||
"google_bigquery",
|
||||
"google_books",
|
||||
"google_calendar",
|
||||
@@ -167,4 +168,4 @@
|
||||
"zep",
|
||||
"zoom"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,9 @@ Generate completions using Perplexity AI chat models
|
||||
| `max_tokens` | number | No | Maximum number of tokens to generate \(e.g., 1024, 2048, 4096\) |
|
||||
| `temperature` | number | No | Sampling temperature between 0 and 1 \(e.g., 0.0 for deterministic, 0.7 for creative\) |
|
||||
| `apiKey` | string | Yes | Perplexity API key |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -78,6 +81,8 @@ Get ranked search results from Perplexity
|
||||
| `search_after_date` | string | No | Include only content published after this date \(format: MM/DD/YYYY\) |
|
||||
| `search_before_date` | string | No | Include only content published before this date \(format: MM/DD/YYYY\) |
|
||||
| `apiKey` | string | Yes | Perplexity API key |
|
||||
| `pricing` | per_request | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@ A powerful web search tool that provides access to Google search results through
|
||||
| `hl` | string | No | Language code for search results \(e.g., "en", "es", "de", "fr"\) |
|
||||
| `type` | string | No | Type of search to perform \(e.g., "search", "news", "images", "videos", "places", "shopping"\) |
|
||||
| `apiKey` | string | Yes | Serper API Key |
|
||||
| `pricing` | custom | No | No description |
|
||||
| `metadata` | string | No | No description |
|
||||
| `rateLimit` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
301
apps/sim/blocks/blocks/google_analytics.ts
Normal file
301
apps/sim/blocks/blocks/google_analytics.ts
Normal file
@@ -0,0 +1,301 @@
|
||||
import { GoogleAnalyticsIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { AuthMode } from '@/blocks/types'
|
||||
import { getScopesForService } from '@/lib/oauth/utils'
|
||||
import type { GoogleAnalyticsResponse } from '@/tools/google_analytics/types'
|
||||
|
||||
export const GoogleAnalyticsBlock: BlockConfig<GoogleAnalyticsResponse> = {
|
||||
type: 'google_analytics',
|
||||
name: 'Google Analytics',
|
||||
description: 'Query GA4 analytics data and reports',
|
||||
authMode: AuthMode.OAuth,
|
||||
longDescription:
|
||||
'Integrate Google Analytics GA4 into your workflow. Run custom reports, get realtime data, and discover available dimensions and metrics.',
|
||||
docsLink: 'https://docs.sim.ai/tools/google_analytics',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: GoogleAnalyticsIcon,
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Run Report', id: 'run_report' },
|
||||
{ label: 'Run Realtime Report', id: 'run_realtime_report' },
|
||||
{ label: 'Get Metadata', id: 'get_metadata' },
|
||||
],
|
||||
value: () => 'run_report',
|
||||
},
|
||||
{
|
||||
id: 'credential',
|
||||
title: 'Google Analytics Account',
|
||||
type: 'oauth-input',
|
||||
canonicalParamId: 'oauthCredential',
|
||||
mode: 'basic',
|
||||
required: true,
|
||||
serviceId: 'google-analytics',
|
||||
requiredScopes: getScopesForService('google-analytics'),
|
||||
placeholder: 'Select Google Analytics account',
|
||||
},
|
||||
{
|
||||
id: 'manualCredential',
|
||||
title: 'Google Analytics Account',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'oauthCredential',
|
||||
mode: 'advanced',
|
||||
placeholder: 'Enter credential ID',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'propertyId',
|
||||
title: 'Property ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'GA4 property ID (e.g., 123456789)',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'metrics',
|
||||
title: 'Metrics',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., activeUsers,sessions,screenPageViews',
|
||||
condition: { field: 'operation', value: ['run_report', 'run_realtime_report'] },
|
||||
required: { field: 'operation', value: ['run_report', 'run_realtime_report'] },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a comma-separated list of GA4 metric API names based on the user's description.
|
||||
Common metrics: activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conversions, totalRevenue, newUsers, engagedSessions, engagementRate, eventsPerSession, eventCount, totalUsers.
|
||||
Return ONLY the comma-separated metric names - no explanations, no extra text.`,
|
||||
placeholder: 'Describe the metrics you want...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'dimensions',
|
||||
title: 'Dimensions',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., date,country,deviceCategory',
|
||||
condition: { field: 'operation', value: 'run_report' },
|
||||
required: { field: 'operation', value: 'run_report' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a comma-separated list of GA4 dimension API names based on the user's description.
|
||||
Common dimensions: date, country, city, deviceCategory, browser, operatingSystem, sessionSource, sessionMedium, sessionCampaignName, pagePath, pageTitle, landingPage, language, newVsReturning.
|
||||
Return ONLY the comma-separated dimension names - no explanations, no extra text.`,
|
||||
placeholder: 'Describe the dimensions you want...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'realtimeDimensions',
|
||||
title: 'Dimensions',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., unifiedScreenName,country (optional)',
|
||||
condition: { field: 'operation', value: 'run_realtime_report' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a comma-separated list of GA4 realtime dimension API names.
|
||||
Common realtime dimensions: unifiedScreenName, country, city, deviceCategory, platform, streamName, audienceName.
|
||||
Return ONLY the comma-separated dimension names - no explanations, no extra text.`,
|
||||
placeholder: 'Describe the dimensions you want...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'startDate',
|
||||
title: 'Start Date',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., 7daysAgo, 30daysAgo, 2024-01-01',
|
||||
condition: { field: 'operation', value: 'run_report' },
|
||||
required: { field: 'operation', value: 'run_report' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: 'Generate a GA4 date string. Supported formats: YYYY-MM-DD, or relative dates like "today", "yesterday", "NdaysAgo" (e.g., "7daysAgo", "30daysAgo"). Return ONLY the date string.',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'endDate',
|
||||
title: 'End Date',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., today, yesterday, 2024-12-31',
|
||||
condition: { field: 'operation', value: 'run_report' },
|
||||
required: { field: 'operation', value: 'run_report' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: 'Generate a GA4 date string. Supported formats: YYYY-MM-DD, or relative dates like "today", "yesterday", "NdaysAgo" (e.g., "7daysAgo", "30daysAgo"). Return ONLY the date string.',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'dimensionFilter',
|
||||
title: 'Dimension Filter',
|
||||
type: 'long-input',
|
||||
placeholder: 'JSON filter (e.g., {"filter":{"fieldName":"country","stringFilter":{"value":"US"}}})',
|
||||
condition: { field: 'operation', value: ['run_report', 'run_realtime_report'] },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a GA4 dimension filter JSON object.
|
||||
Format: {"filter":{"fieldName":"dimensionName","stringFilter":{"matchType":"EXACT","value":"filterValue"}}}
|
||||
For multiple filters use: {"andGroup":{"expressions":[...]}} or {"orGroup":{"expressions":[...]}}
|
||||
Match types: EXACT, BEGINS_WITH, ENDS_WITH, CONTAINS, FULL_REGEXP, PARTIAL_REGEXP.
|
||||
Return ONLY valid JSON - no explanations.`,
|
||||
generationType: 'json-object',
|
||||
placeholder: 'Describe how to filter dimensions...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'metricFilter',
|
||||
title: 'Metric Filter',
|
||||
type: 'long-input',
|
||||
placeholder: 'JSON filter for metrics',
|
||||
condition: { field: 'operation', value: ['run_report', 'run_realtime_report'] },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a GA4 metric filter JSON object.
|
||||
Format: {"filter":{"fieldName":"metricName","numericFilter":{"operation":"GREATER_THAN","value":{"int64Value":"100"}}}}
|
||||
Operations: EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL.
|
||||
Return ONLY valid JSON - no explanations.`,
|
||||
generationType: 'json-object',
|
||||
placeholder: 'Describe how to filter metrics...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'orderBys',
|
||||
title: 'Order By',
|
||||
type: 'long-input',
|
||||
placeholder: 'JSON array (e.g., [{"metric":{"metricName":"activeUsers"},"desc":true}])',
|
||||
condition: { field: 'operation', value: 'run_report' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a GA4 orderBys JSON array.
|
||||
Format for metric sort: [{"metric":{"metricName":"metricName"},"desc":true}]
|
||||
Format for dimension sort: [{"dimension":{"dimensionName":"dimensionName"},"desc":false}]
|
||||
Return ONLY valid JSON array - no explanations.`,
|
||||
generationType: 'json-object',
|
||||
placeholder: 'Describe how to sort results...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'limit',
|
||||
title: 'Row Limit',
|
||||
type: 'short-input',
|
||||
placeholder: 'Max rows to return (default: 10000)',
|
||||
condition: { field: 'operation', value: ['run_report', 'run_realtime_report'] },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'offset',
|
||||
title: 'Row Offset',
|
||||
type: 'short-input',
|
||||
placeholder: 'Starting row for pagination (default: 0)',
|
||||
condition: { field: 'operation', value: 'run_report' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'startMinutesAgo',
|
||||
title: 'Start Minutes Ago',
|
||||
type: 'short-input',
|
||||
placeholder: 'Start of time window in minutes ago (default: 29)',
|
||||
condition: { field: 'operation', value: 'run_realtime_report' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'endMinutesAgo',
|
||||
title: 'End Minutes Ago',
|
||||
type: 'short-input',
|
||||
placeholder: 'End of time window in minutes ago (default: 0)',
|
||||
condition: { field: 'operation', value: 'run_realtime_report' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'keepEmptyRows',
|
||||
title: 'Keep Empty Rows',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'No (default)', id: '' },
|
||||
{ label: 'Yes', id: 'true' },
|
||||
],
|
||||
placeholder: 'Include rows with all zero metric values',
|
||||
condition: { field: 'operation', value: 'run_report' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'currencyCode',
|
||||
title: 'Currency Code',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., USD, EUR',
|
||||
condition: { field: 'operation', value: 'run_report' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
'google_analytics_run_report',
|
||||
'google_analytics_run_realtime_report',
|
||||
'google_analytics_get_metadata',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
switch (params.operation) {
|
||||
case 'run_report':
|
||||
return 'google_analytics_run_report'
|
||||
case 'run_realtime_report':
|
||||
return 'google_analytics_run_realtime_report'
|
||||
case 'get_metadata':
|
||||
return 'google_analytics_get_metadata'
|
||||
default:
|
||||
throw new Error(`Invalid Google Analytics operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const { oauthCredential, realtimeDimensions, keepEmptyRows, ...rest } = params
|
||||
|
||||
return {
|
||||
oauthCredential,
|
||||
...rest,
|
||||
dimensions: params.operation === 'run_realtime_report'
|
||||
? realtimeDimensions
|
||||
: rest.dimensions,
|
||||
limit: rest.limit ? Number.parseInt(rest.limit as string, 10) : undefined,
|
||||
offset: rest.offset ? Number.parseInt(rest.offset as string, 10) : undefined,
|
||||
startMinutesAgo: rest.startMinutesAgo
|
||||
? Number.parseInt(rest.startMinutesAgo as string, 10)
|
||||
: undefined,
|
||||
endMinutesAgo: rest.endMinutesAgo
|
||||
? Number.parseInt(rest.endMinutesAgo as string, 10)
|
||||
: undefined,
|
||||
keepEmptyRows: keepEmptyRows === 'true' ? true : undefined,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
oauthCredential: { type: 'string', description: 'Google Analytics access token' },
|
||||
propertyId: { type: 'string', description: 'GA4 property ID' },
|
||||
metrics: { type: 'string', description: 'Comma-separated metric names' },
|
||||
dimensions: { type: 'string', description: 'Comma-separated dimension names' },
|
||||
realtimeDimensions: { type: 'string', description: 'Comma-separated realtime dimension names' },
|
||||
startDate: { type: 'string', description: 'Report start date' },
|
||||
endDate: { type: 'string', description: 'Report end date' },
|
||||
dimensionFilter: { type: 'string', description: 'Dimension filter JSON' },
|
||||
metricFilter: { type: 'string', description: 'Metric filter JSON' },
|
||||
orderBys: { type: 'string', description: 'Order by specification JSON' },
|
||||
limit: { type: 'string', description: 'Maximum rows to return' },
|
||||
offset: { type: 'string', description: 'Starting row offset' },
|
||||
startMinutesAgo: { type: 'string', description: 'Realtime start minutes ago' },
|
||||
endMinutesAgo: { type: 'string', description: 'Realtime end minutes ago' },
|
||||
keepEmptyRows: { type: 'string', description: 'Include rows with all zero metric values' },
|
||||
currencyCode: { type: 'string', description: 'Currency code for revenue metrics' },
|
||||
},
|
||||
outputs: {
|
||||
dimensionHeaders: { type: 'json', description: 'Dimension column headers' },
|
||||
metricHeaders: { type: 'json', description: 'Metric column headers' },
|
||||
rows: { type: 'json', description: 'Report data rows' },
|
||||
rowCount: { type: 'number', description: 'Total number of rows' },
|
||||
metadata: { type: 'json', description: 'Report metadata (currency, timezone)' },
|
||||
dimensions: { type: 'json', description: 'Available dimensions (from get_metadata)' },
|
||||
metrics: { type: 'json', description: 'Available metrics (from get_metadata)' },
|
||||
},
|
||||
}
|
||||
@@ -53,6 +53,7 @@ import { GmailBlock, GmailV2Block } from '@/blocks/blocks/gmail'
|
||||
import { GongBlock } from '@/blocks/blocks/gong'
|
||||
import { GoogleSearchBlock } from '@/blocks/blocks/google'
|
||||
import { GoogleAdsBlock } from '@/blocks/blocks/google_ads'
|
||||
import { GoogleAnalyticsBlock } from '@/blocks/blocks/google_analytics'
|
||||
import { GoogleBigQueryBlock } from '@/blocks/blocks/google_bigquery'
|
||||
import { GoogleBooksBlock } from '@/blocks/blocks/google_books'
|
||||
import { GoogleCalendarBlock, GoogleCalendarV2Block } from '@/blocks/blocks/google_calendar'
|
||||
@@ -261,6 +262,7 @@ export const registry: Record<string, BlockConfig> = {
|
||||
google_calendar: GoogleCalendarBlock,
|
||||
google_calendar_v2: GoogleCalendarV2Block,
|
||||
google_ads: GoogleAdsBlock,
|
||||
google_analytics: GoogleAnalyticsBlock,
|
||||
google_books: GoogleBooksBlock,
|
||||
google_contacts: GoogleContactsBlock,
|
||||
google_docs: GoogleDocsBlock,
|
||||
|
||||
@@ -3600,6 +3600,25 @@ export const ResendIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const GoogleAnalyticsIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'>
|
||||
<g transform='translate(-174.95 -339.18)scale(3.54856)'>
|
||||
<path
|
||||
d='M149.3 112.8V221c0 12.1 8.4 18.9 17.2 18.9 8.2 0 17.2-5.7 17.2-18.9V113.6c0-11.1-8.2-18-17.2-18s-17.2 7.6-17.2 17.2'
|
||||
fill='#f8ab00'
|
||||
/>
|
||||
<path
|
||||
d='M104.2 167.7V221c0 12.1 8.4 18.9 17.2 18.9 8.2 0 17.2-5.7 17.2-18.9v-52.5c0-11.1-8.2-18-17.2-18s-17.2 7.7-17.2 17.2'
|
||||
fill='#e37300'
|
||||
/>
|
||||
<path
|
||||
d='M93.6 222.7c0 9.5-7.7 17.2-17.2 17.2s-17.2-7.7-17.2-17.2 7.7-17.2 17.2-17.2 17.2 7.6 17.2 17.2'
|
||||
fill='#e37300'
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const GoogleAdsIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>
|
||||
<g transform='matrix(.257748 0 0 .257745 -.361416 2.515516)'>
|
||||
|
||||
@@ -970,6 +970,41 @@ export const auth = betterAuth({
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
providerId: 'google-analytics',
|
||||
clientId: env.GOOGLE_CLIENT_ID as string,
|
||||
clientSecret: env.GOOGLE_CLIENT_SECRET as string,
|
||||
discoveryUrl: 'https://accounts.google.com/.well-known/openid-configuration',
|
||||
accessType: 'offline',
|
||||
scopes: getCanonicalScopesForProvider('google-analytics'),
|
||||
prompt: 'consent',
|
||||
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/google-analytics`,
|
||||
getUserInfo: async (tokens) => {
|
||||
try {
|
||||
const response = await fetch('https://openidconnect.googleapis.com/v1/userinfo', {
|
||||
headers: { Authorization: `Bearer ${tokens.accessToken}` },
|
||||
})
|
||||
if (\!response.ok) {
|
||||
logger.error('Failed to fetch Google user info', { status: response.status })
|
||||
throw new Error(`Failed to fetch Google user info: ${response.statusText}`)
|
||||
}
|
||||
const profile = await response.json()
|
||||
const now = new Date()
|
||||
return {
|
||||
id: `${profile.sub}-${crypto.randomUUID()}`,
|
||||
name: profile.name || 'Google User',
|
||||
email: profile.email,
|
||||
image: profile.picture || undefined,
|
||||
emailVerified: profile.email_verified || false,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error in Google getUserInfo', { error })
|
||||
throw error
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
providerId: 'google-ads',
|
||||
clientId: env.GOOGLE_CLIENT_ID as string,
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
DropboxIcon,
|
||||
GmailIcon,
|
||||
GoogleAdsIcon,
|
||||
GoogleAnalyticsIcon,
|
||||
GoogleBigQueryIcon,
|
||||
GoogleCalendarIcon,
|
||||
GoogleContactsIcon,
|
||||
@@ -147,6 +148,18 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
|
||||
'https://www.googleapis.com/auth/contacts',
|
||||
],
|
||||
},
|
||||
'google-analytics': {
|
||||
name: 'Google Analytics',
|
||||
description: 'Query GA4 analytics data, run reports, and get realtime metrics.',
|
||||
providerId: 'google-analytics',
|
||||
icon: GoogleAnalyticsIcon,
|
||||
baseProviderIcon: GoogleIcon,
|
||||
scopes: [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'https://www.googleapis.com/auth/analytics.readonly',
|
||||
],
|
||||
},
|
||||
'google-ads': {
|
||||
name: 'Google Ads',
|
||||
description: 'Query campaigns, ad groups, and performance metrics in Google Ads.',
|
||||
|
||||
@@ -9,6 +9,7 @@ export type OAuthProvider =
|
||||
| 'google-calendar'
|
||||
| 'google-contacts'
|
||||
| 'google-ads'
|
||||
| 'google-analytics'
|
||||
| 'google-bigquery'
|
||||
| 'google-tasks'
|
||||
| 'google-vault'
|
||||
@@ -57,6 +58,7 @@ export type OAuthService =
|
||||
| 'google-calendar'
|
||||
| 'google-contacts'
|
||||
| 'google-ads'
|
||||
| 'google-analytics'
|
||||
| 'google-bigquery'
|
||||
| 'google-tasks'
|
||||
| 'google-vault'
|
||||
|
||||
@@ -24,6 +24,7 @@ export const SCOPE_DESCRIPTIONS: Record<string, string> = {
|
||||
'https://www.googleapis.com/auth/userinfo.profile': 'View basic profile info',
|
||||
'https://www.googleapis.com/auth/forms.body': 'View and manage Google Forms',
|
||||
'https://www.googleapis.com/auth/forms.responses.readonly': 'View responses to Google Forms',
|
||||
'https://www.googleapis.com/auth/analytics.readonly': 'Read-only access to Google Analytics data',
|
||||
'https://www.googleapis.com/auth/adwords': 'Manage Google Ads campaigns and reporting',
|
||||
'https://www.googleapis.com/auth/bigquery': 'View and manage data in Google BigQuery',
|
||||
'https://www.googleapis.com/auth/ediscovery': 'Access Google Vault for eDiscovery',
|
||||
|
||||
113
apps/sim/tools/google_analytics/get_metadata.ts
Normal file
113
apps/sim/tools/google_analytics/get_metadata.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
GoogleAnalyticsGetMetadataParams,
|
||||
GoogleAnalyticsGetMetadataResponse,
|
||||
} from '@/tools/google_analytics/types'
|
||||
|
||||
export const getMetadataTool: ToolConfig<
|
||||
GoogleAnalyticsGetMetadataParams,
|
||||
GoogleAnalyticsGetMetadataResponse
|
||||
> = {
|
||||
id: 'google_analytics_get_metadata',
|
||||
name: 'Get Google Analytics Metadata',
|
||||
description:
|
||||
'Get available dimensions, metrics, and their descriptions for a Google Analytics GA4 property',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-analytics',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'The access token for the Google Analytics API',
|
||||
},
|
||||
propertyId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'The GA4 property ID (e.g., 123456789). Use 0 to get universal metadata available across all properties.',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://analyticsdata.googleapis.com/v1beta/properties/${params.propertyId.trim()}/metadata`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to get Google Analytics metadata')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
dimensions: (data.dimensions ?? []).map(
|
||||
(d: { apiName: string; uiName: string; description: string; category: string }) => ({
|
||||
apiName: d.apiName ?? '',
|
||||
uiName: d.uiName ?? '',
|
||||
description: d.description ?? '',
|
||||
category: d.category ?? '',
|
||||
})
|
||||
),
|
||||
metrics: (data.metrics ?? []).map(
|
||||
(m: {
|
||||
apiName: string
|
||||
uiName: string
|
||||
description: string
|
||||
category: string
|
||||
type: string
|
||||
}) => ({
|
||||
apiName: m.apiName ?? '',
|
||||
uiName: m.uiName ?? '',
|
||||
description: m.description ?? '',
|
||||
category: m.category ?? '',
|
||||
type: m.type ?? '',
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
dimensions: {
|
||||
type: 'array',
|
||||
description: 'Available dimensions for the property',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
apiName: { type: 'string', description: 'API name to use in report requests' },
|
||||
uiName: { type: 'string', description: 'Human-readable display name' },
|
||||
description: { type: 'string', description: 'Description of the dimension' },
|
||||
category: { type: 'string', description: 'Category grouping' },
|
||||
},
|
||||
},
|
||||
},
|
||||
metrics: {
|
||||
type: 'array',
|
||||
description: 'Available metrics for the property',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
apiName: { type: 'string', description: 'API name to use in report requests' },
|
||||
uiName: { type: 'string', description: 'Human-readable display name' },
|
||||
description: { type: 'string', description: 'Description of the metric' },
|
||||
category: { type: 'string', description: 'Category grouping' },
|
||||
type: { type: 'string', description: 'Data type of the metric' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
9
apps/sim/tools/google_analytics/index.ts
Normal file
9
apps/sim/tools/google_analytics/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { getMetadataTool } from '@/tools/google_analytics/get_metadata'
|
||||
import { runRealtimeReportTool } from '@/tools/google_analytics/run_realtime_report'
|
||||
import { runReportTool } from '@/tools/google_analytics/run_report'
|
||||
|
||||
export const googleAnalyticsRunReportTool = runReportTool
|
||||
export const googleAnalyticsRunRealtimeReportTool = runRealtimeReportTool
|
||||
export const googleAnalyticsGetMetadataTool = getMetadataTool
|
||||
|
||||
export * from './types'
|
||||
185
apps/sim/tools/google_analytics/run_realtime_report.ts
Normal file
185
apps/sim/tools/google_analytics/run_realtime_report.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
GoogleAnalyticsRunRealtimeReportParams,
|
||||
GoogleAnalyticsRunRealtimeReportResponse,
|
||||
} from '@/tools/google_analytics/types'
|
||||
|
||||
export const runRealtimeReportTool: ToolConfig<
|
||||
GoogleAnalyticsRunRealtimeReportParams,
|
||||
GoogleAnalyticsRunRealtimeReportResponse
|
||||
> = {
|
||||
id: 'google_analytics_run_realtime_report',
|
||||
name: 'Run Google Analytics Realtime Report',
|
||||
description: 'Run a realtime report on Google Analytics GA4 property data from the last 30 minutes',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-analytics',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'The access token for the Google Analytics API',
|
||||
},
|
||||
propertyId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The GA4 property ID (e.g., 123456789)',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated dimension names for realtime data (e.g., unifiedScreenName,country,deviceCategory)',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated metric names (e.g., activeUsers,screenPageViews,conversions)',
|
||||
},
|
||||
dimensionFilter: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Dimension filter as JSON',
|
||||
},
|
||||
metricFilter: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Metric filter as JSON',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of rows to return (default: 10000, max: 250000)',
|
||||
},
|
||||
startMinutesAgo: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start of the time window in minutes ago (default: 29, max: 29 for standard, 59 for 360)',
|
||||
},
|
||||
endMinutesAgo: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End of the time window in minutes ago (default: 0, meaning now)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://analyticsdata.googleapis.com/v1beta/properties/${params.propertyId.trim()}:runRealtimeReport`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
metrics: params.metrics
|
||||
.split(',')
|
||||
.map((m: string) => ({ name: m.trim() })),
|
||||
}
|
||||
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions
|
||||
.split(',')
|
||||
.map((d: string) => ({ name: d.trim() }))
|
||||
}
|
||||
if (params.dimensionFilter) {
|
||||
body.dimensionFilter = JSON.parse(params.dimensionFilter)
|
||||
}
|
||||
if (params.metricFilter) {
|
||||
body.metricFilter = JSON.parse(params.metricFilter)
|
||||
}
|
||||
if (params.limit !== undefined) {
|
||||
body.limit = params.limit
|
||||
}
|
||||
if (params.startMinutesAgo !== undefined || params.endMinutesAgo !== undefined) {
|
||||
body.minuteRanges = [
|
||||
{
|
||||
startMinutesAgo: params.startMinutesAgo ?? 29,
|
||||
endMinutesAgo: params.endMinutesAgo ?? 0,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to run Google Analytics realtime report')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
dimensionHeaders: data.dimensionHeaders ?? [],
|
||||
metricHeaders: data.metricHeaders ?? [],
|
||||
rows: data.rows ?? [],
|
||||
rowCount: data.rowCount ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
dimensionHeaders: {
|
||||
type: 'array',
|
||||
description: 'Dimension column headers',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Dimension name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
metricHeaders: {
|
||||
type: 'array',
|
||||
description: 'Metric column headers',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Metric name' },
|
||||
type: { type: 'string', description: 'Metric data type' },
|
||||
},
|
||||
},
|
||||
},
|
||||
rows: {
|
||||
type: 'array',
|
||||
description: 'Realtime report data rows',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
dimensionValues: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values for this row',
|
||||
},
|
||||
metricValues: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values for this row',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
rowCount: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the result',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
230
apps/sim/tools/google_analytics/run_report.ts
Normal file
230
apps/sim/tools/google_analytics/run_report.ts
Normal file
@@ -0,0 +1,230 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
GoogleAnalyticsRunReportParams,
|
||||
GoogleAnalyticsRunReportResponse,
|
||||
} from '@/tools/google_analytics/types'
|
||||
|
||||
export const runReportTool: ToolConfig<
|
||||
GoogleAnalyticsRunReportParams,
|
||||
GoogleAnalyticsRunReportResponse
|
||||
> = {
|
||||
id: 'google_analytics_run_report',
|
||||
name: 'Run Google Analytics Report',
|
||||
description: 'Run a customized report on Google Analytics GA4 property data',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-analytics',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'The access token for the Google Analytics API',
|
||||
},
|
||||
propertyId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The GA4 property ID (e.g., 123456789)',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated dimension names (e.g., date,country,deviceCategory). See GA4 dimensions reference.',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated metric names (e.g., activeUsers,sessions,screenPageViews). See GA4 metrics reference.',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date in YYYY-MM-DD format, or relative dates like "7daysAgo", "30daysAgo", "yesterday"',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date in YYYY-MM-DD format, or "today", "yesterday"',
|
||||
},
|
||||
dimensionFilter: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Dimension filter as JSON (e.g., {"filter":{"fieldName":"country","stringFilter":{"value":"US"}}})',
|
||||
},
|
||||
metricFilter: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Metric filter as JSON (e.g., {"filter":{"fieldName":"activeUsers","numericFilter":{"operation":"GREATER_THAN","value":{"int64Value":"100"}}}})',
|
||||
},
|
||||
orderBys: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Order by specification as JSON array (e.g., [{"metric":{"metricName":"activeUsers"},"desc":true}])',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of rows to return (default: 10000, max: 250000)',
|
||||
},
|
||||
offset: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Starting row offset for pagination (default: 0)',
|
||||
},
|
||||
keepEmptyRows: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to include rows with all zero metric values',
|
||||
},
|
||||
currencyCode: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Currency code for revenue metrics (e.g., USD, EUR)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://analyticsdata.googleapis.com/v1beta/properties/${params.propertyId.trim()}:runReport`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
dimensions: params.dimensions
|
||||
.split(',')
|
||||
.map((d: string) => ({ name: d.trim() })),
|
||||
metrics: params.metrics
|
||||
.split(',')
|
||||
.map((m: string) => ({ name: m.trim() })),
|
||||
dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],
|
||||
}
|
||||
|
||||
if (params.dimensionFilter) {
|
||||
body.dimensionFilter = JSON.parse(params.dimensionFilter)
|
||||
}
|
||||
if (params.metricFilter) {
|
||||
body.metricFilter = JSON.parse(params.metricFilter)
|
||||
}
|
||||
if (params.orderBys) {
|
||||
body.orderBys = JSON.parse(params.orderBys)
|
||||
}
|
||||
if (params.limit !== undefined) {
|
||||
body.limit = params.limit
|
||||
}
|
||||
if (params.offset !== undefined) {
|
||||
body.offset = params.offset
|
||||
}
|
||||
if (params.keepEmptyRows !== undefined) {
|
||||
body.keepEmptyRows = params.keepEmptyRows
|
||||
}
|
||||
if (params.currencyCode) {
|
||||
body.currencyCode = params.currencyCode
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to run Google Analytics report')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
dimensionHeaders: data.dimensionHeaders ?? [],
|
||||
metricHeaders: data.metricHeaders ?? [],
|
||||
rows: data.rows ?? [],
|
||||
rowCount: data.rowCount ?? null,
|
||||
metadata: data.metadata
|
||||
? {
|
||||
currencyCode: data.metadata.currencyCode ?? null,
|
||||
timeZone: data.metadata.timeZone ?? null,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
dimensionHeaders: {
|
||||
type: 'array',
|
||||
description: 'Dimension column headers',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Dimension name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
metricHeaders: {
|
||||
type: 'array',
|
||||
description: 'Metric column headers',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Metric name' },
|
||||
type: { type: 'string', description: 'Metric data type' },
|
||||
},
|
||||
},
|
||||
},
|
||||
rows: {
|
||||
type: 'array',
|
||||
description: 'Report data rows',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
dimensionValues: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values for this row',
|
||||
},
|
||||
metricValues: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values for this row',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
rowCount: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the result',
|
||||
optional: true,
|
||||
},
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Report metadata including currency code and time zone',
|
||||
optional: true,
|
||||
properties: {
|
||||
currencyCode: { type: 'string', description: 'Currency code used in the report' },
|
||||
timeZone: { type: 'string', description: 'Time zone used in the report' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
97
apps/sim/tools/google_analytics/types.ts
Normal file
97
apps/sim/tools/google_analytics/types.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
export interface GoogleAnalyticsRunReportParams {
|
||||
accessToken: string
|
||||
propertyId: string
|
||||
dimensions: string
|
||||
metrics: string
|
||||
startDate: string
|
||||
endDate: string
|
||||
dimensionFilter?: string
|
||||
metricFilter?: string
|
||||
orderBys?: string
|
||||
limit?: number
|
||||
offset?: number
|
||||
keepEmptyRows?: boolean
|
||||
currencyCode?: string
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsRunRealtimeReportParams {
|
||||
accessToken: string
|
||||
propertyId: string
|
||||
dimensions?: string
|
||||
metrics: string
|
||||
dimensionFilter?: string
|
||||
metricFilter?: string
|
||||
limit?: number
|
||||
startMinutesAgo?: number
|
||||
endMinutesAgo?: number
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsGetMetadataParams {
|
||||
accessToken: string
|
||||
propertyId: string
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsDimensionHeader {
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsMetricHeader {
|
||||
name: string
|
||||
type: string
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsRow {
|
||||
dimensionValues: Array<{ value: string }>
|
||||
metricValues: Array<{ value: string }>
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsRunReportResponse extends ToolResponse {
|
||||
output: {
|
||||
dimensionHeaders: GoogleAnalyticsDimensionHeader[]
|
||||
metricHeaders: GoogleAnalyticsMetricHeader[]
|
||||
rows: GoogleAnalyticsRow[]
|
||||
rowCount: number | null
|
||||
metadata: {
|
||||
currencyCode: string | null
|
||||
timeZone: string | null
|
||||
} | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsRunRealtimeReportResponse extends ToolResponse {
|
||||
output: {
|
||||
dimensionHeaders: GoogleAnalyticsDimensionHeader[]
|
||||
metricHeaders: GoogleAnalyticsMetricHeader[]
|
||||
rows: GoogleAnalyticsRow[]
|
||||
rowCount: number | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsDimensionMetadata {
|
||||
apiName: string
|
||||
uiName: string
|
||||
description: string
|
||||
category: string
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsMetricMetadata {
|
||||
apiName: string
|
||||
uiName: string
|
||||
description: string
|
||||
category: string
|
||||
type: string
|
||||
}
|
||||
|
||||
export interface GoogleAnalyticsGetMetadataResponse extends ToolResponse {
|
||||
output: {
|
||||
dimensions: GoogleAnalyticsDimensionMetadata[]
|
||||
metrics: GoogleAnalyticsMetricMetadata[]
|
||||
}
|
||||
}
|
||||
|
||||
export type GoogleAnalyticsResponse =
|
||||
| GoogleAnalyticsRunReportResponse
|
||||
| GoogleAnalyticsRunRealtimeReportResponse
|
||||
| GoogleAnalyticsGetMetadataResponse
|
||||
@@ -797,6 +797,11 @@ import {
|
||||
googleDriveUpdateTool,
|
||||
googleDriveUploadTool,
|
||||
} from '@/tools/google_drive'
|
||||
import {
|
||||
googleAnalyticsGetMetadataTool,
|
||||
googleAnalyticsRunRealtimeReportTool,
|
||||
googleAnalyticsRunReportTool,
|
||||
} from '@/tools/google_analytics'
|
||||
import {
|
||||
googleFormsBatchUpdateTool,
|
||||
googleFormsCreateFormTool,
|
||||
@@ -3305,6 +3310,9 @@ export const tools: Record<string, ToolConfig> = {
|
||||
revenuecat_defer_google_subscription: revenuecatDeferGoogleSubscriptionTool,
|
||||
revenuecat_refund_google_subscription: revenuecatRefundGoogleSubscriptionTool,
|
||||
revenuecat_revoke_google_subscription: revenuecatRevokeGoogleSubscriptionTool,
|
||||
google_analytics_run_report: googleAnalyticsRunReportTool,
|
||||
google_analytics_run_realtime_report: googleAnalyticsRunRealtimeReportTool,
|
||||
google_analytics_get_metadata: googleAnalyticsGetMetadataTool,
|
||||
google_drive_copy: googleDriveCopyTool,
|
||||
google_drive_create_folder: googleDriveCreateFolderTool,
|
||||
google_drive_delete: googleDriveDeleteTool,
|
||||
|
||||
Reference in New Issue
Block a user