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

Laravel Optimizely Laravel Package

jeffersongoncalves/laravel-optimizely

Integrate Optimizely with Laravel using this package for feature flags, experiments, and A/B testing. It provides configuration and convenient helpers to evaluate decisions and track events in your Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install with Composer and publish the config:
    composer require <vendor>/<package>
    php artisan vendor:publish --tag=optimizely-config
    
  2. Set the minimum required environment variables:
    OPTIMIZELY_API_TOKEN=your-personal-access-token
    OPTIMIZELY_PROJECT_ID=123456789
    # OPTIMIZELY_BASE_URL=https://api.optimizely.com/v2
    # OPTIMIZELY_PER_PAGE=50
    
  3. Start with the resource that answers the most common day-to-day question: what experiments are running right now?
    use Vendor\Optimizely\Facades\Optimizely;
    
    $running = Optimizely::experiments()
        ->forProject(config('optimizely.project_id'))
        ->status('running')
        ->list();
    
  4. Look first at:
    • config/optimizely.php — default project id, base URL, and per-page size
    • the service provider binding — whether the client is a singleton or resolved per call
    • the exception class — OptimizelyException exposes the decoded API error body, so start debugging there rather than in the HTTP layer

The first realistic use case is a read-only dashboard or scheduled sync: list projects, list experiments filtered by status, and pull results for completed experiments.

Implementation Patterns

Resolve the default project explicitly. The configurable default project id is convenient, but most production code should pass the project id from your own model rather than relying on global config:

$experiments = Optimizely::experiments()
    ->forProject($site->optimizely_project_id)
    ->list();

Use list calls as the entry point, then get by id. The package exposes list/get pairs for projects, experiments, campaigns, audiences, events, and pages. A common pattern is to sync list endpoints into local tables on a schedule, then fetch individual resources only when you need full detail or results.

Filter experiments server-side. The experiment list supports a status filter; use it rather than pulling everything and filtering in PHP:

$paused = Optimizely::experiments()
    ->forProject($projectId)
    ->status('paused')
    ->list();

Treat create/update payloads as raw API arrays. The package is a thin client; build payloads from your own form requests or DTOs and pass them through. Keep a dedicated action class per resource so you can validate required fields before the HTTP call:

$experiment = Optimizely::experiments()->create($projectId, [
    'name' => 'Checkout test',
    'type' => 'a/b',
    // ...
]);

Use results endpoints from queued jobs, not web requests. Campaign and experiment results are heavier calls and often feed reporting screens. Dispatch a job, cache the decoded response, and let the UI read from cache. Invalidate the cache when an experiment is updated or archived.

Wrap mutations in a transaction-like flow. Archive and update are separate API calls. If your domain requires both, record intent locally first, call the API, then reconcile with a get to confirm the final state.

Catch OptimizelyException at the boundary. The decoded error body is the useful part. A typical pattern:

try {
    Optimizely::experiments()->update($projectId, $experimentId, $payload);
} catch (OptimizelyException $e) {
    report($e);
    // $e->getResponseBody() is an array with the API's message/errors
    throw ValidationException::withMessages([
        'optimizely' => $e->getResponseBody()['message'] ?? 'Optimizely request failed',
    ]);
}

Paginate deliberately. Set a sane per_page in config and handle the pagination metadata returned by list endpoints. For sync jobs, loop until the API indicates no further pages, and persist a cursor or last-synced timestamp so reruns are idempotent.

Keep a single client instance per request/job. If the package binds the client as a singleton, reusing it avoids repeated config resolution. In long-running queue workers, verify that the client does not cache stale project state across jobs.

Gotchas and Tips

  • The default project id is not a substitute for an explicit project id. Endpoints like campaigns, audiences, events, and pages still need a project context. Pass it explicitly in any multi-tenant or multi-project application.
  • per_page is capped by the API. Setting it very high in config will not necessarily return more records; always read the pagination metadata rather than assuming count($items) < $perPage means you are done.
  • Update semantics differ by resource. Some updates are partial and only require changed fields; others may require a fuller representation. If an update unexpectedly clears fields, fetch the resource first, merge, and send the merged payload.
  • Archive is not delete. Archived experiments disappear from normal lists but remain retrievable by id in many cases. Do not use archive as a hard delete in your local data model; mark records archived locally and keep the id.
  • Results can lag behind experiment changes. Do not assume a result is available immediately after an experiment is updated or stopped. Poll with backoff or display a "results pending" state.
  • OptimizelyException bodies are decoded but not guaranteed to be arrays. The API can return a string body or an unexpected shape on gateway errors. Guard with is_array() before indexing into the body.
  • Do not log the API token. The config value is easy to leak through dd(config('optimizely')) or exception context. Use a redacted config dump or a dedicated debug command.
  • Remember config:cache. If you change the default project id or base URL in .env, run php artisan config:cache in cached environments, otherwise the old value persists in queue workers and Octane processes.
  • Handle rate limits at the job level. A 429 from the API should release the job with backoff rather than failing permanently. Centralize this in a middleware or in the job's retryUntil.
  • Base URL changes affect every resource. If you point the client at a different base URL for testing, confirm the path prefixes expected by the package; a trailing slash or missing version segment will produce 404s that look like auth errors.
  • Extension point: bind your own client wrapper. If you need retries, logging, or metrics, decorate the package client in a service provider rather than scattering try/catch blocks across controllers and jobs.
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