Skip to content

feat(apify): add app-rankings-tool for iOS & Android top charts#327

Merged
zhubzy merged 2 commits intomainfrom
feat/app-rankings-tool
Mar 19, 2026
Merged

feat(apify): add app-rankings-tool for iOS & Android top charts#327
zhubzy merged 2 commits intomainfrom
feat/app-rankings-tool

Conversation

@zhubzy
Copy link
Contributor

@zhubzy zhubzy commented Mar 19, 2026

Summary

  • Adds app-rankings-tool as a built-in ToolBubble wrapping the slothtechlabs/ios-android-app-rankings-scraper Apify actor
  • Supports both Apple App Store and Google Play in a single call — free, paid, and grossing charts across 60+ countries and 50+ categories
  • Includes full Zod input/output schemas with validated enums for countries, Apple category IDs, and Google category slugs

Changes

  • New: actors/app-rankings-scraper.ts — Apify actor input/output Zod schemas
  • New: tool-bubble/app-rankings-tool.ts — ToolBubble wrapper with unified interface, full category reference in description
  • Modified: Actor registry, bubble factory, available-tools, shared-schemas (BubbleName + credential mapping)

Test plan

  • OSS build passes (76 bubbles in manifest)
  • get-bubble app-rankings-tool returns full schema via MCP
  • Created and ran a test flow via MCP — 20 apps returned in 6.5s
  • DX tested by 5 independent subagents building real flows — all feedback incorporated (renamed chartTypeschartType, added full category reference, clarified param types and limit semantics)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added App Rankings tool to scrape Apple App Store and Google Play ranking data with configurable parameters including stores, countries, categories, chart types, and result limits.
  • Chores

    • Version updates across packages.

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>
Copilot AI review requested due to automatic review settings March 19, 2026 04:57
@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 86cac063-916f-4879-bdd4-f66b6fc74256

📥 Commits

Reviewing files that changed from the base of the PR and between b2a3576 and 00025b2.

📒 Files selected for processing (7)
  • packages/bubble-core/package.json
  • packages/bubble-runtime/package.json
  • packages/bubble-scope-manager/package.json
  • packages/bubble-shared-schemas/package.json
  • packages/create-bubblelab-app/package.json
  • packages/create-bubblelab-app/templates/basic/package.json
  • packages/create-bubblelab-app/templates/reddit-scraper/package.json

📝 Walkthrough

Walkthrough

This PR introduces an AppRankingsTool that scrapes Apple App Store and Google Play app rankings via an Apify actor integration. It includes validation schemas, tool implementation with credential verification, factory registration, type definitions, and credential mappings, with coordinated package version updates.

Changes

Cohort / File(s) Summary
App Rankings Tool Implementation
packages/bubble-core/src/bubbles/tool-bubble/app-rankings-tool.ts, packages/bubble-core/src/bubbles/service-bubble/apify/actors/app-rankings-scraper.ts
New tool class with performAction() and scrapeRankings() methods that validate credentials, call the Apify actor, and normalize output rankings. Accompanying scraper schemas define allowlists for Apple/Google stores, countries, categories, and chart types with strict validation constraints.
Apify Actor Registry
packages/bubble-core/src/bubbles/service-bubble/apify/apify-scraper.schema.ts, packages/bubble-core/src/bubbles/service-bubble/apify/apify.ts
Registered new Apify actor slothtechlabs/ios-android-app-rankings-scraper in the schema registry with input/output schemas and metadata; updated documentation to list the new supported actor.
Factory & Module Exports
packages/bubble-core/src/bubble-factory.ts, packages/bubble-core/src/bubbles/service-bubble/apify/index.ts, packages/bubble-core/src/index.ts
Registered app-rankings-tool in the bubble factory with dynamic import; re-exported scraper schemas from Apify index; exported AppRankingsTool from main package entrypoint.
Type & Credential Definitions
packages/bubble-core/src/types/available-tools.ts, packages/bubble-shared-schemas/src/types.ts, packages/bubble-shared-schemas/src/credential-schema.ts
Added app-rankings-tool to AvailableTools enum and BubbleName union; added credential pool interface and mapped app-rankings-tool to CredentialType.APIFY_CRED in credential options.
Package Version Updates
packages/bubble-core/package.json, packages/bubble-runtime/package.json, packages/bubble-scope-manager/package.json, packages/bubble-shared-schemas/package.json, packages/create-bubblelab-app/package.json, packages/create-bubblelab-app/templates/*/package.json
Bumped all related package versions from 0.1.237 to 0.1.238.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • iqbalbhatti49

Poem

🐰 A ranking tool hops into view,
With Apify magic, both old and new!
Apple and Google, now side by side,
Bubbles unite with credential pride! 🎪
From scraped-at timestamps to genres galore,
One small release brings app rankings galore! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a new app-rankings-tool for fetching iOS and Android app charts. It is specific to the changeset and accurately reflects the primary feature addition.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/app-rankings-tool
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 19, 2026

Deploying bubblelab-documentation with  Cloudflare Pages  Cloudflare Pages

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

View logs

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 AppRankingsTool with 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.

Comment on lines +242 to +250
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,
Comment on lines +175 to +178
googleCountries: z
.array(z.enum(APPLE_COUNTRIES))
.default(['us'])
.optional()
Comment on lines +178 to +210
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,
};
}
Comment on lines +49 to +71
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"]'
),
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/bubble-core/src/bubbles/service-bubble/apify/actors/app-rankings-scraper.ts (1)

175-179: googleCountries correctly uses APPLE_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_COUNTRIES is correct. For improved code clarity, consider renaming APPLE_COUNTRIES to SUPPORTED_COUNTRIES to reflect that it covers both stores, or explicitly define GOOGLE_COUNTRIES as an alias to APPLE_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

📥 Commits

Reviewing files that changed from the base of the PR and between caeb2c6 and a9b476e.

📒 Files selected for processing (10)
  • packages/bubble-core/src/bubble-factory.ts
  • packages/bubble-core/src/bubbles/service-bubble/apify/actors/app-rankings-scraper.ts
  • packages/bubble-core/src/bubbles/service-bubble/apify/apify-scraper.schema.ts
  • packages/bubble-core/src/bubbles/service-bubble/apify/apify.ts
  • packages/bubble-core/src/bubbles/service-bubble/apify/index.ts
  • packages/bubble-core/src/bubbles/tool-bubble/app-rankings-tool.ts
  • packages/bubble-core/src/index.ts
  • packages/bubble-core/src/types/available-tools.ts
  • packages/bubble-shared-schemas/src/credential-schema.ts
  • packages/bubble-shared-schemas/src/types.ts

Comment on lines +242 to +254
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'
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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>
@zhubzy zhubzy force-pushed the feat/app-rankings-tool branch from b2a3576 to 00025b2 Compare March 19, 2026 05:16
@zhubzy zhubzy merged commit 2d65bfa into main Mar 19, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants