feat(apify): add app-rankings-tool for iOS & Android top charts#327
feat(apify): add app-rankings-tool for iOS & Android top charts#327
Conversation
Built-in tool bubble wrapping the slothtechlabs/ios-android-app-rankings-scraper Apify actor. Supports both Apple App Store and Google Play in a single call with free/paid/grossing charts across 60+ countries and 50+ categories. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR introduces an Changes
Sequence DiagramsequenceDiagram
actor Client
participant AppRankingsTool
participant Validator as Zod Schemas
participant ApifyBubble
participant ApifyActor as Apify Actor<br/>(ios-android-app-rankings-scraper)
Client->>AppRankingsTool: performAction(params)
AppRankingsTool->>Validator: Validate input params
Validator-->>AppRankingsTool: Valid params
AppRankingsTool->>AppRankingsTool: Check APIFY_CRED credential
alt Missing Credential
AppRankingsTool-->>Client: Error result (empty rankings)
else Credential Present
AppRankingsTool->>AppRankingsTool: scrapeRankings()
AppRankingsTool->>AppRankingsTool: Map chartType to actor IDs
AppRankingsTool->>ApifyBubble: Call with actor input<br/>(stores, countries, categories, charts, limit)
ApifyBubble->>ApifyActor: Execute scraper task
ApifyActor-->>ApifyBubble: Return items list
ApifyBubble-->>AppRankingsTool: Actor result
AppRankingsTool->>AppRankingsTool: transformRankings()<br/>(normalize fields)
AppRankingsTool->>Validator: Validate output schema
Validator-->>AppRankingsTool: Valid output
AppRankingsTool-->>Client: Success result with rankings
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying bubblelab-documentation with
|
| Latest commit: |
00025b2
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://41c5ecc8.bubblelab-documentation.pages.dev |
| Branch Preview URL: | https://feat-app-rankings-tool.bubblelab-documentation.pages.dev |
There was a problem hiding this comment.
Pull request overview
Adds a new Apify-backed tool bubble (app-rankings-tool) to scrape iOS App Store and Google Play top charts via the slothtechlabs/ios-android-app-rankings-scraper actor, and wires it into the bubble registry/tooling surfaces.
Changes:
- Introduces
AppRankingsToolwith unified input/output schemas and Apify execution wiring. - Adds Apify actor input/output Zod schemas for the app rankings scraper and registers the actor in the Apify schema registry.
- Registers the new bubble name across shared schemas, credential mapping, available tools, exports, and bubble factory.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/bubble-shared-schemas/src/types.ts | Adds app-rankings-tool to the BubbleName union. |
| packages/bubble-shared-schemas/src/credential-schema.ts | Adds a credential pool entry interface and maps app-rankings-tool to APIFY_CRED. |
| packages/bubble-core/src/types/available-tools.ts | Adds app-rankings-tool to the AvailableTools enum. |
| packages/bubble-core/src/index.ts | Exports AppRankingsTool from the package entrypoint. |
| packages/bubble-core/src/bubbles/tool-bubble/app-rankings-tool.ts | New tool bubble: params/result schemas, Apify actor invocation, and output transformation. |
| packages/bubble-core/src/bubbles/service-bubble/apify/index.ts | Re-exports app rankings actor schemas. |
| packages/bubble-core/src/bubbles/service-bubble/apify/apify.ts | Updates integrated-actors documentation list to include the new actor/tool. |
| packages/bubble-core/src/bubbles/service-bubble/apify/apify-scraper.schema.ts | Registers the new Apify actor schemas in APIFY_ACTOR_SCHEMAS. |
| packages/bubble-core/src/bubbles/service-bubble/apify/actors/app-rankings-scraper.ts | New Zod schemas/types for the app rankings actor input/output. |
| packages/bubble-core/src/bubble-factory.ts | Registers app-rankings-tool for creation/import in the bubble factory. |
You can also share your feedback on Copilot code review. Take the survey.
| const scraper = | ||
| new ApifyBubble<'slothtechlabs/ios-android-app-rankings-scraper'>( | ||
| { | ||
| actorId: 'slothtechlabs/ios-android-app-rankings-scraper', | ||
| input, | ||
| waitForFinish: true, | ||
| timeout: 300000, | ||
| limit: stores.length * countries.length * limit, | ||
| credentials: this.params.credentials, |
| googleCountries: z | ||
| .array(z.enum(APPLE_COUNTRIES)) | ||
| .default(['us']) | ||
| .optional() |
| async performAction(): Promise<AppRankingsToolResult> { | ||
| const credentials = this.params.credentials; | ||
| if (!credentials || !credentials[CredentialType.APIFY_CRED]) { | ||
| return this.createErrorResult( | ||
| 'App rankings scraping requires authentication. Please configure APIFY_CRED.' | ||
| ); | ||
| } | ||
|
|
||
| try { | ||
| const result = await this.scrapeRankings(); | ||
| return { | ||
| operation: 'rankings', | ||
| rankings: result.rankings, | ||
| totalApps: result.rankings.length, | ||
| success: result.success, | ||
| error: result.error, | ||
| }; | ||
| } catch (error) { | ||
| return this.createErrorResult( | ||
| error instanceof Error ? error.message : 'Unknown error occurred' | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| private createErrorResult(errorMessage: string): AppRankingsToolResult { | ||
| return { | ||
| operation: 'rankings', | ||
| rankings: [], | ||
| totalApps: 0, | ||
| success: false, | ||
| error: errorMessage, | ||
| }; | ||
| } |
| countries: z | ||
| .array(z.string()) | ||
| .default(['us']) | ||
| .optional() | ||
| .describe( | ||
| 'Array of ISO 3166-1 alpha-2 country codes. Default: ["us"]. Example: ["us", "jp", "de"]' | ||
| ), | ||
|
|
||
| appleCategories: z | ||
| .array(z.string()) | ||
| .default(['overall']) | ||
| .optional() | ||
| .describe( | ||
| 'Array of Apple category IDs. Use "overall" for all apps. Common IDs: "6014" (Games), "6015" (Finance), "6013" (Health & Fitness), "6020" (Medical), "6016" (Entertainment), "6005" (Social Networking), "6007" (Productivity), "6002" (Utilities), "6017" (Education), "6008" (Lifestyle). Default: ["overall"]' | ||
| ), | ||
|
|
||
| googleCategories: z | ||
| .array(z.string()) | ||
| .default(['APPLICATION']) | ||
| .optional() | ||
| .describe( | ||
| 'Array of Google Play category IDs. Use "APPLICATION" for all apps. Common values: "GAME", "FINANCE", "HEALTH_AND_FITNESS", "MEDICAL", "ENTERTAINMENT", "SOCIAL", "PRODUCTIVITY", "TOOLS", "EDUCATION", "LIFESTYLE". Default: ["APPLICATION"]' | ||
| ), |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/bubble-core/src/bubbles/service-bubble/apify/actors/app-rankings-scraper.ts (1)
175-179:googleCountriescorrectly usesAPPLE_COUNTRIES— both stores support identical countries.Both the Google Play Store and Apple App Store are supported using the same set of 60+ ISO country codes. Since the country lists are identical, using
APPLE_COUNTRIESis correct. For improved code clarity, consider renamingAPPLE_COUNTRIEStoSUPPORTED_COUNTRIESto reflect that it covers both stores, or explicitly defineGOOGLE_COUNTRIESas an alias toAPPLE_COUNTRIES.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bubble-core/src/bubbles/service-bubble/apify/actors/app-rankings-scraper.ts` around lines 175 - 179, The schema uses APPLE_COUNTRIES for googleCountries; keep functionality but clarify intent by either renaming the constant APPLE_COUNTRIES to SUPPORTED_COUNTRIES across its definition and all usages (including the schema property googleCountries) or create a new alias export GOOGLE_COUNTRIES = APPLE_COUNTRIES and update the schema to import/use GOOGLE_COUNTRIES instead; update any imports/usages (e.g., in app-rankings-scraper.ts referencing APPLE_COUNTRIES) so names are consistent and tests/builds still pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/bubble-core/src/bubbles/tool-bubble/app-rankings-tool.ts`:
- Around line 242-254: The limit passed to the ApifyBubble constructor
(ApifyBubble<'slothtechlabs/ios-android-app-rankings-scraper'>) currently uses
stores.length * countries.length * limit but ignores categories, which can cause
truncation; update the calculation to include category count by computing
categoryCount = (input.appleCategories?.length ?? 0) +
(input.googleCategories?.length ?? 0) || 1 and then set the limit to
stores.length * countries.length * categoryCount * limit (use these symbols:
input, appleCategories, googleCategories, ApifyBubble, and the limit parameter)
so the actor receives enough allowance when multiple categories are specified.
---
Nitpick comments:
In
`@packages/bubble-core/src/bubbles/service-bubble/apify/actors/app-rankings-scraper.ts`:
- Around line 175-179: The schema uses APPLE_COUNTRIES for googleCountries; keep
functionality but clarify intent by either renaming the constant APPLE_COUNTRIES
to SUPPORTED_COUNTRIES across its definition and all usages (including the
schema property googleCountries) or create a new alias export GOOGLE_COUNTRIES =
APPLE_COUNTRIES and update the schema to import/use GOOGLE_COUNTRIES instead;
update any imports/usages (e.g., in app-rankings-scraper.ts referencing
APPLE_COUNTRIES) so names are consistent and tests/builds still pass.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 96ae759f-db6e-42cc-ae00-581609f46954
📒 Files selected for processing (10)
packages/bubble-core/src/bubble-factory.tspackages/bubble-core/src/bubbles/service-bubble/apify/actors/app-rankings-scraper.tspackages/bubble-core/src/bubbles/service-bubble/apify/apify-scraper.schema.tspackages/bubble-core/src/bubbles/service-bubble/apify/apify.tspackages/bubble-core/src/bubbles/service-bubble/apify/index.tspackages/bubble-core/src/bubbles/tool-bubble/app-rankings-tool.tspackages/bubble-core/src/index.tspackages/bubble-core/src/types/available-tools.tspackages/bubble-shared-schemas/src/credential-schema.tspackages/bubble-shared-schemas/src/types.ts
| const scraper = | ||
| new ApifyBubble<'slothtechlabs/ios-android-app-rankings-scraper'>( | ||
| { | ||
| actorId: 'slothtechlabs/ios-android-app-rankings-scraper', | ||
| input, | ||
| waitForFinish: true, | ||
| timeout: 300000, | ||
| limit: stores.length * countries.length * limit, | ||
| credentials: this.params.credentials, | ||
| }, | ||
| this.context, | ||
| 'appRankingsScraper' | ||
| ); |
There was a problem hiding this comment.
Limit calculation may truncate results when multiple categories are specified.
The current calculation stores.length * countries.length * limit doesn't account for category multipliers. When users specify multiple appleCategories or googleCategories, the actual item count from the actor could exceed this limit, causing truncation.
For example: 2 stores × 2 countries × 2 categories each × 100 limit = 800 items, but the formula yields only 400.
🔧 Proposed fix
+ // Calculate expected items: each store/country/category combo returns up to `limit` apps
+ const appleCount = stores.includes('apple')
+ ? countries.length * appleCategories.length
+ : 0;
+ const googleCount = stores.includes('google')
+ ? countries.length * googleCategories.length
+ : 0;
+ const expectedItems = (appleCount + googleCount) * limit;
+
const scraper =
new ApifyBubble<'slothtechlabs/ios-android-app-rankings-scraper'>(
{
actorId: 'slothtechlabs/ios-android-app-rankings-scraper',
input,
waitForFinish: true,
timeout: 300000,
- limit: stores.length * countries.length * limit,
+ limit: expectedItems,
credentials: this.params.credentials,
},
this.context,
'appRankingsScraper'
);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/bubble-core/src/bubbles/tool-bubble/app-rankings-tool.ts` around
lines 242 - 254, The limit passed to the ApifyBubble constructor
(ApifyBubble<'slothtechlabs/ios-android-app-rankings-scraper'>) currently uses
stores.length * countries.length * limit but ignores categories, which can cause
truncation; update the calculation to include category count by computing
categoryCount = (input.appleCategories?.length ?? 0) +
(input.googleCategories?.length ?? 0) || 1 and then set the limit to
stores.length * countries.length * categoryCount * limit (use these symbols:
input, appleCategories, googleCategories, ApifyBubble, and the limit parameter)
so the actor receives enough allowance when multiple categories are specified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
b2a3576 to
00025b2
Compare
Summary
app-rankings-toolas a built-in ToolBubble wrapping theslothtechlabs/ios-android-app-rankings-scraperApify actorChanges
actors/app-rankings-scraper.ts— Apify actor input/output Zod schemastool-bubble/app-rankings-tool.ts— ToolBubble wrapper with unified interface, full category reference in descriptionTest plan
get-bubble app-rankings-toolreturns full schema via MCPchartTypes→chartType, added full category reference, clarified param types and limit semantics)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores