Klaviyo API Integration mit Drupal 11 & Drupal Commerce
Klaviyo API Integration mit Drupal 11
Klaviyo ist der Goldstandard für E-Commerce E-Mail-Marketing. Warenkorbabbrecher-E-Mails, personalisierte Produktempfehlungen, Post-Purchase-Flows – alles basierend auf echtem Kundenverhalten.
In diesem Guide zeige ich, wie Sie Klaviyo über die API v3 in Drupal 11 und Drupal Commerce integrieren.
Warum Klaviyo für E-Commerce?
- E-Commerce-DNA: Klaviyo versteht Bestellungen, Produkte, Warenkörbe nativ
- Predictive Analytics: Vorhersagen zu Customer Lifetime Value und Churn-Risiko
- Segmentierung: Dynamische Segmente basierend auf Kaufverhalten
- Flows: Automatisierte Sequenzen für jeden Touchpoint der Customer Journey
- SMS-Marketing: E-Mail und SMS aus einer Plattform
Die Architektur
┌─────────────────────┐ ┌─────────────────────┐
│ Drupal 11 │ │ Klaviyo │
│ Drupal Commerce │───────▶│ E-Mail & SMS │
└─────────────────────┘ └─────────────────────┘
│ │
▼ ▼
Events tracken: Automatisiert:
- Viewed Product - Warenkorbabbrecher
- Added to Cart - Willkommensserien
- Started Checkout - Post-Purchase
- Placed Order - Win-Back
- Fulfilled Order - Browse Abandonment
1. Klaviyo API Setup
API Key erstellen
- In Klaviyo: Account → Settings → API Keys
- “Create Private API Key” klicken
- Berechtigungen setzen:
- Profiles: Full Access
- Events: Full Access
- Catalogs: Full Access
- Lists: Full Access
Den Private Key sicher speichern – er wird nur einmal angezeigt.
2. Drupal Custom Module erstellen
Modulstruktur
modules/custom/klaviyo_integration/
├── klaviyo_integration.info.yml
├── klaviyo_integration.module
├── klaviyo_integration.services.yml
├── config/
│ └── install/
│ └── klaviyo_integration.settings.yml
└── src/
├── Form/
│ └── KlaviyoSettingsForm.php
└── Service/
└── KlaviyoClient.php
klaviyo_integration.info.yml
name: Klaviyo Integration
type: module
description: 'Klaviyo API Integration für E-Commerce Tracking'
core_version_requirement: ^10 || ^11
package: Custom
dependencies:
- drupal:commerce_order
- drupal:commerce_cart
API Client Service
<?php
// src/Service/KlaviyoClient.php
namespace Drupal\klaviyo_integration\Service;
use Drupal\Core\Config\ConfigFactoryInterface;
use GuzzleHttp\ClientInterface;
use Psr\Log\LoggerInterface;
class KlaviyoClient {
protected string $apiKey;
protected string $baseUrl = 'https://a.klaviyo.com/api';
protected ClientInterface $httpClient;
protected LoggerInterface $logger;
public function __construct(
ConfigFactoryInterface $configFactory,
ClientInterface $httpClient,
LoggerInterface $logger
) {
$config = $configFactory->get('klaviyo_integration.settings');
$this->apiKey = $config->get('api_key') ?? '';
$this->httpClient = $httpClient;
$this->logger = $logger;
}
/**
* Profil erstellen oder aktualisieren.
*/
public function upsertProfile(array $profileData): ?array {
$payload = [
'data' => [
'type' => 'profile',
'attributes' => $profileData,
],
];
return $this->request('POST', '/profile-import', $payload);
}
/**
* Event tracken (z.B. Viewed Product, Added to Cart).
*/
public function trackEvent(string $eventName, array $properties, string $email): ?array {
$payload = [
'data' => [
'type' => 'event',
'attributes' => [
'metric' => [
'data' => [
'type' => 'metric',
'attributes' => [
'name' => $eventName,
],
],
],
'profile' => [
'data' => [
'type' => 'profile',
'attributes' => [
'email' => $email,
],
],
],
'properties' => $properties,
'time' => date('c'),
],
],
];
return $this->request('POST', '/events', $payload);
}
/**
* Produkt zum Katalog hinzufügen.
*/
public function syncProduct(array $productData): ?array {
$catalogId = 'DRUPAL_COMMERCE'; // Ihr Katalog-ID
$payload = [
'data' => [
'type' => 'catalog-item',
'attributes' => [
'external_id' => $productData['sku'],
'catalog_type' => '$default',
'title' => $productData['title'],
'description' => $productData['description'] ?? '',
'url' => $productData['url'],
'image_full_url' => $productData['image_url'] ?? '',
'price' => $productData['price'],
],
],
];
return $this->request('POST', '/catalog-items', $payload);
}
/**
* HTTP Request an Klaviyo API.
*/
protected function request(string $method, string $endpoint, array $payload = []): ?array {
try {
$response = $this->httpClient->request($method, $this->baseUrl . $endpoint, [
'headers' => [
'Authorization' => 'Klaviyo-API-Key ' . $this->apiKey,
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'revision' => '2024-10-15', // API Revision
],
'json' => $payload,
]);
return json_decode($response->getBody()->getContents(), TRUE);
}
catch (\Exception $e) {
$this->logger->error('Klaviyo API error: @message', [
'@message' => $e->getMessage(),
]);
return NULL;
}
}
}
Services registrieren
# klaviyo_integration.services.yml
services:
klaviyo_integration.client:
class: Drupal\klaviyo_integration\Service\KlaviyoClient
arguments:
- '@config.factory'
- '@http_client'
- '@logger.channel.klaviyo_integration'
logger.channel.klaviyo_integration:
parent: logger.channel_base
arguments: ['klaviyo_integration']
3. E-Commerce Events tracken
Event Subscriber für Commerce Events
<?php
// src/EventSubscriber/CommerceEventSubscriber.php
namespace Drupal\klaviyo_integration\EventSubscriber;
use Drupal\commerce_cart\Event\CartEntityAddEvent;
use Drupal\commerce_order\Event\OrderEvent;
use Drupal\klaviyo_integration\Service\KlaviyoClient;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CommerceEventSubscriber implements EventSubscriberInterface {
protected KlaviyoClient $klaviyoClient;
public function __construct(KlaviyoClient $klaviyoClient) {
$this->klaviyoClient = $klaviyoClient;
}
public static function getSubscribedEvents(): array {
return [
'commerce_cart.entity.add' => 'onAddToCart',
'commerce_order.place.post_transition' => 'onOrderPlaced',
];
}
/**
* "Added to Cart" Event tracken.
*/
public function onAddToCart(CartEntityAddEvent $event): void {
$cart = $event->getCart();
$orderItem = $event->getOrderItem();
$purchasedEntity = $orderItem->getPurchasedEntity();
$email = $cart->getEmail();
if (empty($email)) {
return;
}
$properties = [
'ProductName' => $purchasedEntity->getTitle(),
'ProductID' => $purchasedEntity->getSku(),
'Quantity' => (int) $orderItem->getQuantity(),
'Price' => (float) $orderItem->getUnitPrice()->getNumber(),
'Currency' => $orderItem->getUnitPrice()->getCurrencyCode(),
'ProductURL' => $purchasedEntity->toUrl('canonical', ['absolute' => TRUE])->toString(),
'CartTotal' => (float) $cart->getTotalPrice()->getNumber(),
];
$this->klaviyoClient->trackEvent('Added to Cart', $properties, $email);
}
/**
* "Placed Order" Event tracken.
*/
public function onOrderPlaced(OrderEvent $event): void {
$order = $event->getOrder();
$email = $order->getEmail();
if (empty($email)) {
return;
}
// Bestellte Produkte sammeln
$items = [];
foreach ($order->getItems() as $item) {
$purchasedEntity = $item->getPurchasedEntity();
$items[] = [
'ProductID' => $purchasedEntity->getSku(),
'ProductName' => $purchasedEntity->getTitle(),
'Quantity' => (int) $item->getQuantity(),
'Price' => (float) $item->getUnitPrice()->getNumber(),
];
}
$properties = [
'OrderID' => $order->getOrderNumber(),
'OrderTotal' => (float) $order->getTotalPrice()->getNumber(),
'Currency' => $order->getTotalPrice()->getCurrencyCode(),
'Items' => $items,
'ItemCount' => count($items),
'BillingAddress' => $this->formatAddress($order->getBillingProfile()),
];
$this->klaviyoClient->trackEvent('Placed Order', $properties, $email);
// Profil mit Kundendaten aktualisieren
$this->klaviyoClient->upsertProfile([
'email' => $email,
'first_name' => $order->getBillingProfile()?->get('address')[0]?->given_name ?? '',
'last_name' => $order->getBillingProfile()?->get('address')[0]?->family_name ?? '',
'properties' => [
'last_order_date' => date('c'),
'total_orders' => 1, // Sollte inkrementiert werden
],
]);
}
protected function formatAddress($profile): array {
if (!$profile) {
return [];
}
$address = $profile->get('address')[0] ?? NULL;
if (!$address) {
return [];
}
return [
'city' => $address->locality ?? '',
'country' => $address->country_code ?? '',
'zip' => $address->postal_code ?? '',
];
}
}
4. JavaScript Tracking für Browse-Verhalten
Viewed Product tracken
<?php
// In einem Preprocess Hook oder Controller
/**
* Implements hook_preprocess_commerce_product().
*/
function klaviyo_integration_preprocess_commerce_product(&$variables) {
$product = $variables['product_entity'];
$variation = $product->getDefaultVariation();
$variables['#attached']['drupalSettings']['klaviyo'] = [
'productId' => $variation->getSku(),
'productName' => $product->getTitle(),
'price' => (float) $variation->getPrice()->getNumber(),
'currency' => $variation->getPrice()->getCurrencyCode(),
'url' => $product->toUrl('canonical', ['absolute' => TRUE])->toString(),
'imageUrl' => '', // Bild-URL hier einfügen
];
$variables['#attached']['library'][] = 'klaviyo_integration/tracking';
}
JavaScript Library
// js/klaviyo-tracking.js
(function (Drupal, drupalSettings) {
'use strict';
Drupal.behaviors.klaviyoTracking = {
attach: function (context, settings) {
if (!settings.klaviyo || !window._learnq) {
return;
}
const product = settings.klaviyo;
// Viewed Product Event
window._learnq.push(['track', 'Viewed Product', {
ProductID: product.productId,
ProductName: product.productName,
Price: product.price,
Currency: product.currency,
ProductURL: product.url,
ImageURL: product.imageUrl
}]);
}
};
})(Drupal, drupalSettings);
Klaviyo Snippet einbinden
/**
* Implements hook_page_attachments().
*/
function klaviyo_integration_page_attachments(array &$attachments) {
$config = \Drupal::config('klaviyo_integration.settings');
$publicKey = $config->get('public_key');
if ($publicKey) {
$attachments['#attached']['html_head'][] = [
[
'#type' => 'html_tag',
'#tag' => 'script',
'#attributes' => [
'async' => TRUE,
'src' => 'https://static.klaviyo.com/onsite/js/klaviyo.js?company_id=' . $publicKey,
],
],
'klaviyo_script',
];
}
}
5. Produktkatalog synchronisieren
Für personalisierte Produktempfehlungen braucht Klaviyo Ihren Produktkatalog:
<?php
// Drush Command oder Cron Job
/**
* Alle Produkte zu Klaviyo synchronisieren.
*/
public function syncAllProducts(): void {
$productStorage = \Drupal::entityTypeManager()->getStorage('commerce_product');
$products = $productStorage->loadMultiple();
foreach ($products as $product) {
$variation = $product->getDefaultVariation();
if (!$variation) {
continue;
}
$this->klaviyoClient->syncProduct([
'sku' => $variation->getSku(),
'title' => $product->getTitle(),
'description' => strip_tags($product->get('body')->value ?? ''),
'url' => $product->toUrl('canonical', ['absolute' => TRUE])->toString(),
'price' => (float) $variation->getPrice()->getNumber(),
'image_url' => $this->getProductImageUrl($product),
]);
}
}
6. Flows in Klaviyo einrichten
Nach der Integration können Sie in Klaviyo automatisierte Flows erstellen:
Warenkorbabbrecher Flow
Trigger: "Added to Cart" Event
Warten: 1 Stunde
Bedingung: Hat NICHT "Placed Order" in den letzten 1 Stunde
→ E-Mail 1: "Sie haben etwas vergessen!"
Warten: 24 Stunden
Bedingung: Hat immer noch nicht bestellt
→ E-Mail 2: "Noch da? 10% Rabatt für Sie"
Warten: 48 Stunden
→ E-Mail 3: "Letzte Chance!"
Post-Purchase Flow
Trigger: "Placed Order" Event
→ E-Mail 1 (sofort): Bestellbestätigung
Warten: 3 Tage
→ E-Mail 2: Versandstatus + Tracking
Warten: 7 Tage nach Lieferung
→ E-Mail 3: Bewertung anfragen
Warten: 30 Tage
→ E-Mail 4: Cross-Selling Empfehlungen
Fazit
Die Klaviyo-Integration mit Drupal 11 erfordert etwas Custom Development, aber das Ergebnis ist ein mächtiges E-Commerce Marketing-System:
- Echtzeit-Tracking aller Kundeninteraktionen
- Automatisierte Flows für jeden Touchpoint
- Personalisierung basierend auf Kaufverhalten
- Messbare ROI durch Conversion-Tracking
Der initiale Aufwand lohnt sich – Klaviyos Warenkorbabbrecher-Flows allein bringen typischerweise 5-15% zusätzlichen Umsatz.
Brauchen Sie Unterstützung bei der Klaviyo-Integration? Kontaktieren Sie mich für ein unverbindliches Gespräch.
Häufig gestellte Fragen (FAQ)
Ist Klaviyo teuer?
Gibt es ein fertiges Drupal-Modul für Klaviyo?
Kann Klaviyo auch ohne Drupal Commerce genutzt werden?
Das könnte Sie auch interessieren
Mautic & Drupal 11: Marketing Automation mit intelligenten Segmenten
So verbinden Sie Mautic mit Drupal 11 für personalisierte Marketing-Kampagnen. Lernen Sie, wie Sie Segmente erstellen un...
DeepL API in Drupal 11 integrieren: Professionelle Übersetzungen automatisieren
Step-by-Step Guide zur Integration der DeepL API in Drupal 11. Automatisieren Sie Content-Übersetzungen mit Custom Modul...
Playwright Tests in Drupal 11: Modernes End-to-End Testing
Praktischer Guide für Playwright End-to-End Tests in Drupal 11. Installation, Konfiguration und Best Practices für autom...