Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Foursquare Api Bundle Laravel Package

jcroll/foursquare-api-bundle

Symfony bundle that integrates the Foursquare API, providing ready-made services and configuration so you can query venues, check-ins, users, tips, and other endpoints directly from your Symfony application.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. It has no service provider, no facade, no config publish tag, and no auto-discovery. The bundle itself is just glue around jcroll/foursquare-api-client — and since Laravel does not load Symfony bundles, in a Laravel app you should skip the bundle entirely and install the underlying client, pinned to the 2.x line the bundle itself now targets (v1.1.4 bumps its constraint to ~2.1):

composer require jcroll/foursquare-api-client:^2.1

Then wire it up yourself in config/services.php and a service provider.

// config/services.php
'foursquare' => [
    'client_id'     => env('FOURSQUARE_CLIENT_ID'),
    'client_secret' => env('FOURSQUARE_CLIENT_SECRET'),
    'version'       => env('FOURSQUARE_API_VERSION', '20180605'),
],
// app/Providers/FoursquareServiceProvider.php
use Jcroll\FoursquareApiClient\Client\FoursquareClient;
use Jcroll\FoursquareApiClient\Api\Venues;

public function register(): void
{
    $this->app->singleton(FoursquareClient::class, function () {
        return new FoursquareClient([
            'client_id'     => config('services.foursquare.client_id'),
            'client_secret' => config('services.foursquare.client_secret'),
            'version'       => config('services.foursquare.version'),
        ]);
    });

    $this->app->bind(Venues::class, fn ($app) =>
        new Venues($app->make(FoursquareClient::class))
    );
}

Where to look first: open vendor/jcroll/foursquare-api-client/src/Client/FoursquareClient.php and src/Api/Venues.php. That source — not the bundle README — is your actual documentation. The Api/* classes (Venues, Users, Checkins, Photos, Lists) are thin wrappers, one method per endpoint, each returning a decoded JSON array.

First use case: userless venue search. This is the only path that reliably works without an OAuth dance, since it just uses client_id + client_secret.

$results = app(Venues::class)->search([
    'near'  => 'Austin, TX',
    'query' => 'tacos',
    'limit' => 10,
]);

$venues = $results['response']['venues'] ?? [];

If you truly are on Symfony, add JcrollFoursquareApiBundle to AppKernel at ^1.1.4. Note that since 1.1.4 the bundle no longer exposes jcroll_foursquare_api.client_id / jcroll_foursquare_api.client_secret as container parameters — configure the client through the config tree instead, and don't substitute %jcroll_foursquare_api.client_id% anywhere. For a Laravel assessment, that path is a dead end anyway.

Implementation Patterns

Wrap endpoint classes in your own service, never inject them into controllers. The client returns raw arrays with Foursquare's meta/response envelope. Normalize once, then reuse.

final class VenueFinder
{
    public function __construct(private Venues $venues) {}

    /** @return array<int, array{id:string,name:string,lat:float,lng:float}> */
    public function nearby(string $near, string $query, int $limit = 20): array
    {
        $raw = $this->venues->search([
            'near' => $near, 'query' => $query, 'limit' => $limit,
        ]);

        return collect($raw['response']['venues'] ?? [])
            ->map(fn ($v) => [
                'id'   => $v['id'],
                'name' => $v['name'],
                'lat'  => $v['location']['lat'],
                'lng'  => $v['location']['lng'],
            ])
            ->all();
    }
}

Cache aggressively. Foursquare rate limits are per-client_id, and venue data changes slowly. Search results are cheap to memoize; venue details/photo counts are cheaper still.

public function nearby(string $near, string $query): array
{
    return Cache::remember(
        'fsq:search:' . md5("$near|$query"),
        now()->addMinutes(15),
        fn () => $this->search($near, $query)
    );
}

Push enrichment work to the queue. Pulling photos/hours/tips for 50 venues in a request is how you get a 10-second page load. Dispatch a job per venue ID and store the normalized record in your own table.

$venueId = '4b5c8e1af964a5200f0e29e3';
EnrichVenueJob::dispatch($venueId);

OAuth for user-scoped endpoints. checkins, lists, and "friends here now" need a user access token. Keep that as a separate controller + callback route, store the token on your users row, and instantiate a second client with the token. Do not mix userless and user-context calls through one singleton.

Testing. The client is constructed around an HTTP adapter, so inject a fake adapter in tests rather than calling Foursquare. Assert on what your service returns, not on the client's array shape — that shape is the least stable thing in the stack.

$this->mock(Venues::class, function ($mock) {
    $mock->shouldReceive('search')->once()->andReturn([
        'meta' => ['code' => 200],
        'response' => ['venues' => [['id' => 'abc', 'name' => 'Test', 'location' => ['lat' => 1.0, 'lng' => 2.0]]]],
    ]);
});

Gotchas and Tips

  • This package is effectively unmaintained. Long dormant since its original 2016 release; the only activity since has been a config-component bump in the Symfony bundle (v1.1.4) to track jcroll/foursquare-api-client ~2.1. Single-digit stars, no meaningful dependents. Treat it as a reference implementation, not a dependency you can rely on for support. Budget for a fork or a swap.
  • v1.1.4 is bundle-only and technically BC-breaking for Symfony users. Removing client_id/client_secret from the container parameter bag will break any Symfony service definition that injected %jcroll_foursquare_api.client_id%. The maintainer chose not to bump the major. It changes nothing for Laravel — but if you're porting a Symfony snippet into config/services.php, make sure you're porting values, not parameter references.
  • Foursquare's API moved on. The v2 endpoints this client targets (/v2/venues/search, etc.) have been superseded by the newer Places API with different auth headers (Authorization: Bearer <api_key>) and different response envelopes. Apps created recently may not get v2 credentials at all. Verify your account actually has v2 access before writing any code.
  • The v parameter is mandatory. Foursquare requires a YYYYMMDD version string on every request and will change response shapes based on it. Pin it in .env, don't let it default silently, and expect to bump it when Foursquare deprecates a parameter.
  • Errors are not exceptions. The client returns whatever JSON came back; a failed request typically shows up as meta.code != 200 or an empty response. Wrap every call and check meta.code explicitly — otherwise errors surface as mysterious "no venues found."
  • Guzzle version conflicts are likely. A 2016-era client predates Guzzle 7. The 2.1 branch narrows the gap somewhat but doesn't guarantee modern Laravel compatibility. If Composer refuses, you'll need --with-all-dependencies, a fork with the adapter bumped, or to write Http::withToken(...)->get(...) yourself and skip the library entirely.
  • No typed DTOs. Everything is a nested array. One typo in $v['location']['lat'] is a null, not a TypeError. Consider mapping into small value objects at the boundary so the rest of your app isn't array-shaped.
  • Bundle config lives in the Symfony config tree, not in Laravel. Anything in the bundle README about config.yml — including the parameters removed in 1.1.4 — needs translating into config/services.php. Don't copy Symfony service IDs or parameter names.
  • Extension point: since each API class takes the client in its constructor, you can decorate the client (logging, retry, metrics) without touching the endpoint classes — new Venues(new LoggingClient($realClient)) if the adapter is an interface, or just wrap the endpoint classes in your own service layer. That's the cleanest seam in the whole package, and 1.1.4 doesn't disturb it.
  • Keep secrets out of the repo. FOURSQUARE_CLIENT_SECRET goes in .env; add both keys to .env.example with empty values so the next developer isn't guessing.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings