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

Nova Cloudflare Card Laravel Package

zoxta/nova-cloudflare-card

A Laravel Nova card that brings Cloudflare analytics into your admin panel, showing zone traffic, cache hit rates, and threat metrics at a glance. Configurable credentials and a clean dashboard widget make it easy to monitor Cloudflare without leaving Nova.

View on GitHub
Deep Wiki
Context7

Getting Started

Installation

composer require zoxta/nova-cloudflare-card

Nova cards auto-register their assets via the service provider, but you must explicitly tell Nova where to render the card.

Where to look first

  1. composer.json — confirm the package supports your Nova version (laravel/nova is a private dependency so the constraint usually reads something like ^4.0|^5.0). If it pins an older Nova, you will hit a conflict during install.
  2. config/cloudflare.php (after publishing) — this is where API credentials and the target zone live.
  3. src/Cards/CloudflareCard.php — read the component() method and the __construct signature; that tells you exactly what the card accepts.
  4. resources/js/components/Card.vue — see what payload shape the Vue component expects from $this->withMeta() or the card's data() method.

Publish the config/assets

php artisan vendor:publish --tag=cloudflare-card-config
php artisan vendor:publish --tag=cloudflare-card-assets

Configure credentials

Add to .env:

[email protected]
CLOUDFLARE_API_KEY=your-global-api-key
CLOUDFLARE_ZONE_ID=your_zone_id

(Some versions expect an API token with Zone:Analytics:Read scope instead of the email/key pair — check the config file's keys before assuming.)

Register the card

In app/Nova/NovaServiceProvider.php:

public function cards()
{
    return [
        new \Zoxta\NovaCloudflareCard\CloudflareCard(),
    ];
}

Or attach it to a specific dashboard via dashboards() if you want it scoped.

First use case

The most common pattern is a global dashboard tile showing the last 24–30 days of requests, bandwidth, and threat/cache-hit stats for a single Cloudflare zone — a quick "is the site healthy?" glance for ops teams who don't want to open the Cloudflare dashboard.

Implementation Patterns

Scoping the card to a specific zone

Since most installs manage one production zone, pass the zone ID through the card constructor or the config file rather than editing the package:

new CloudflareCard(config('services.cloudflare.zone_id'))

If the constructor doesn't accept arguments, override the value in config/cloudflare.php and cache it per environment.

Per-dashboard placement

Cards can be registered on individual Nova dashboards rather than globally. This is useful if you run a "Marketing" dashboard versus an "Infrastructure" dashboard and only want traffic stats on the latter:

public function dashboards()
{
    return [
        (new Main)->cards([
            new CloudflareCard(),
        ]),
    ];
}

Wrapping the API call for reuse

If you need the same Cloudflare data elsewhere (a custom metric card, a scheduled summary email), extract the GraphQL/REST call into your own service rather than duplicating it. The package almost certainly wraps Cloudflare's GraphQL analytics endpoint (https://api.cloudflare.com/client/v4/graphql); you can mirror the query in an action class and inject it both into your card's data() method and any artisan command.

class CloudflareMetrics
{
    public function forZone(string $zoneId, string $since = '-1440'): array
    {
        // mirror the package's query so card + CLI share a contract
    }
}

Extending the card

Nova cards are just classes with a component() and render()/data() method. If the package's card doesn't expose the fields you need, subclass it and override data():

class ExtendedCloudflareCard extends CloudflareCard
{
    public function component()
    {
        return 'cloudflare-card'; // reuse the Vue component
    }

    public function data()
    {
        return array_merge(parent::data(), [
            'custom' => $this->customMetric(),
        ]);
    }
}

Then reference the new class in NovaServiceProvider.

Multi-zone layouts

For agencies managing several zones, instantiate the card once per zone with a distinct name():

(new CloudflareCard())->name('Cloudflare — Client A'),
(new CloudflareCard('zone_b_id'))->name('Cloudflare — Client B'),

Nova respects name() for the card title; make sure you also cache per-zone so polling doesn't multiply latency.

Caching

Nova cards re-render on every dashboard load. Wrap the package's API call in your own Cache::remember('cf-stats-'.$zoneId, now()->addMinutes(15), ...) if the card itself doesn't cache — otherwise a 6-second Cloudflare GraphQL round-trip makes your dashboard feel broken whenever an ops user refreshes.

Polling

If the Vue component supports refreshIntervalSeconds (many Nova cards do), start at 60 seconds minimum. Cloudflare's free-tier rate limits will bite you at sub-minute polling, and the analytics data doesn't update faster than ~5 minutes anyway.

Gotchas and Tips

Credentials confusion: Key vs Token

Cloudflare has two auth flavours — the legacy global API key (email + key) and scoped API tokens. The package's README or config will hint at one, but it's easy to mix them. Symptom: 403 authentication error or empty graphs even though the zone renders. Verify with:

curl -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID

If that succeeds, the token is fine and the problem is your package config pointing at CLOUDFLARE_API_KEY instead.

Zone ID, not account ID

The GraphQL analytics query filters on zoneTag, which is the zone ID (32-char hex found at the bottom of the Cloudflare zone Overview page). Passing an account ID returns empty datasets without a clear error — you'll just see zeros. Double-check before filing an issue.

GraphQL response shape is deeply nested

Cloudflare returns data.viewer.zones[0].httpRequests1dGroups[0].sum.requests style paths. If the card renders blank but your API call returns 200, log the raw response and diff against the package's parser — a single nullable change in Cloudflare's schema can silently break a hardcoded path.

Asset rebuild after customization

If you edit resources/js (e.g., to adjust the chart), you must run npm run prod inside the package and re-publish assets, or Nova will keep serving the compiled bundle. There's no watch mode tied to your app's Vite server.

Nova 5 vs Nova 4

Nova 5 moved cards to a slightly different lifecycle (component() caching, asset registration via Nova::script). If the package predates Nova 5, cards may render an empty div with a console warning like "Failed to mount component: template or render function not defined." Check the nova peer dependency in composer.json before installing.

Cache poisoning across users

Nova cards render in the authenticated user's session but Cache::remember is global. If you cache the raw API result, fine — if you cache the rendered meta (including user-scoped filters), two admins will see each other's data. Cache the API payload only.

Debugging tip: bypass the card

Drop this in tinker to confirm the failure is in the package versus your config:

app(\Zoxta\NovaCloudflareCard\CloudflareCard::class)->data();

If it throws, you'll get the real exception; Nova swallows errors into a generic "Unable to load card" message, which wastes hours.

Extension points

The card's Vue component is registered globally under the name returned by component(). You can register your own component with the same name before Nova boots to fully replace the UI, or use Nova::script('cloudflare-card-custom', __DIR__.'/dist/custom.js') to layer additional behavior without forking the package.

Maintenance risk

At 10 stars and a single maintainer, treat this as a small utility you may need to patch yourself. Pin the version in composer.json ("zoxta/nova-cloudflare-card": "1.0.*") and vendor-patch rather than relying on upstream fixes. The underlying Cloudflare GraphQL API is stable, so the primary rot risk is Nova version bumps rather than the data layer.

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.
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
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route