DEV Community

Cover image for Hootsuite API Nutzung: Eine Anleitung
Emre Demir
Emre Demir

Posted on • Originally published at apidog.com

Hootsuite API Nutzung: Eine Anleitung

TL;DR

Die Hootsuite API ist ab 2024 nicht mehr öffentlich verfügbar. Für Social-Media-Management-Workflows empfehlen sich jetzt native Plattform-APIs oder spezialisierte Drittanbieter (Buffer, Sprout Social usw.). In diesem Guide findest du praxisorientierte Ansätze für Authentifizierung, Beitragsplanung, Analyse und Teammanagement mit Multi-Plattform-Support.

Teste Apidog noch heute

Hinweis: Hootsuite hat seine öffentliche API ab 2024 eingestellt. Im Folgenden findest du Alternativen wie native Plattform-APIs, Partnerintegrationen und Drittanbieter-APIs mit ähnlichem Funktionsumfang.

Einleitung

Hootsuite verwaltet weltweit über 30 Millionen Social-Media-Konten. Für Entwickler, die Automatisierung im Marketing & Social Media bauen, ist die Anbindung an Social-Media-Plattformen entscheidend.

Die Realität: Social-Media-Manager verlieren wöchentlich 25-35 Stunden durch manuelle Prozesse. Eine API-basierte Integration automatisiert Inhaltsverteilung, Engagement-Tracking und Performance-Reporting.

Hootsuite API Status und Alternativen

Aktuelle API-Situation

Ab 2024 ist die öffentliche Hootsuite API nicht mehr verfügbar. Folgende Alternativen sind relevant:

Ansatz Beschreibung Am besten geeignet für
Native Plattform-APIs Direkte Integration mit Facebook, Twitter, LinkedIn etc. Volle Kontrolle, Custom-Lösungen
Audiense Zielgruppenanalyse (Hootsuite-eigen) Zielgruppenanalyse
HeyOrca Social Media Scheduling API Inhaltskalender
Buffer API Social Media Management Kleine Teams
Sprout Social API Enterprise Social Management Große Organisationen
Agorapulse API Social Media CRM Community-Management

Empfohlener Ansatz: Native Plattform-APIs

Direkte API-Anbindung an Social Networks ist flexibel und zukunftssicher:

Plattform API-Name Hauptfunktionen
Facebook/Instagram Graph API Beiträge, Insights, Kommentare
Twitter/X API v2 Tweets, Analysen, Streams
LinkedIn Marketing API Beiträge, Unternehmensseiten, Anzeigen
Pinterest API v5 Pins, Boards, Analysen
TikTok Display API Videos, User-Infos
YouTube Data API Videos, Playlists, Analysen

Erste Schritte: Multi-Plattform-Authentifizierung

Schritt 1: Entwickler-Apps registrieren

Lege für jede Plattform eine Entwickler-App an und halte die Zugangsdaten sicher:

// Zugangsdaten sicher speichern
const SOCIAL_CREDENTIALS = {
  facebook: {
    appId: process.env.FB_APP_ID,
    appSecret: process.env.FB_APP_SECRET,
    redirectUri: process.env.FB_REDIRECT_URI
  },
  twitter: {
    apiKey: process.env.TWITTER_API_KEY,
    apiSecret: process.env.TWITTER_API_SECRET,
    redirectUri: process.env.TWITTER_REDIRECT_URI
  },
  linkedin: {
    clientId: process.env.LINKEDIN_CLIENT_ID,
    clientSecret: process.env.LINKEDIN_CLIENT_SECRET,
    redirectUri: process.env.LINKEDIN_REDIRECT_URI
  },
  instagram: {
    appId: process.env.FB_APP_ID, // Verwendet Facebook Login
    appSecret: process.env.FB_APP_SECRET
  }
};
Enter fullscreen mode Exit fullscreen mode

Schritt 2: OAuth 2.0-Flow implementieren

Setze einen flexiblen OAuth-Handler für mehrere Plattformen um:

const getAuthUrl = (platform, state) => {
  const configs = {
    facebook: {
      url: 'https://www.facebook.com/v18.0/dialog/oauth',
      params: {
        client_id: SOCIAL_CREDENTIALS.facebook.appId,
        redirect_uri: SOCIAL_CREDENTIALS.facebook.redirectUri,
        scope: 'pages_manage_posts,pages_read_engagement,instagram_basic,instagram_content_publish',
        state
      }
    },
    twitter: {
      url: 'https://twitter.com/i/oauth2/authorize',
      params: {
        client_id: SOCIAL_CREDENTIALS.twitter.apiKey,
        redirect_uri: SOCIAL_CREDENTIALS.twitter.redirectUri,
        scope: 'tweet.read tweet.write users.read offline.access',
        state,
        response_type: 'code'
      }
    },
    linkedin: {
      url: 'https://www.linkedin.com/oauth/v2/authorization',
      params: {
        client_id: SOCIAL_CREDENTIALS.linkedin.clientId,
        redirect_uri: SOCIAL_CREDENTIALS.linkedin.redirectUri,
        scope: 'w_member_social r_basicprofile',
        state,
        response_type: 'code'
      }
    }
  };

  const config = configs[platform];
  const params = new URLSearchParams(config.params);
  return `${config.url}?${params.toString()}`;
};

// OAuth-Callback verarbeiten
const handleOAuthCallback = async (platform, code) => {
  const tokenEndpoints = {
    facebook: 'https://graph.facebook.com/v18.0/oauth/access_token',
    twitter: 'https://api.twitter.com/2/oauth2/token',
    linkedin: 'https://www.linkedin.com/oauth/v2/accessToken'
  };

  const response = await fetch(tokenEndpoints[platform], {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      client_id: SOCIAL_CREDENTIALS[platform].apiKey || SOCIAL_CREDENTIALS[platform].appId || SOCIAL_CREDENTIALS[platform].clientId,
      client_secret: SOCIAL_CREDENTIALS[platform].appSecret || SOCIAL_CREDENTIALS[platform].apiSecret,
      redirect_uri: SOCIAL_CREDENTIALS[platform].redirectUri,
      code,
      grant_type: 'authorization_code'
    })
  });

  return response.json();
};
Enter fullscreen mode Exit fullscreen mode

Schritt 3: Tokens sicher speichern

Speichere Tokens verschlüsselt und mit Metadaten:

// Datenbankschema für soziale Tokens
const SocialToken = {
  userId: 'user_123',
  platform: 'facebook',
  accessToken: 'encrypted_token_here',
  refreshToken: 'encrypted_refresh_token',
  tokenExpiry: Date.now() + 5183999, // 60 Tage
  scopes: ['pages_manage_posts', 'pages_read_engagement'],
  pageId: 'page_456', // Für Facebook/Instagram
  pageName: 'Meine Unternehmensseite'
};
Enter fullscreen mode Exit fullscreen mode

Beitragsplanung und -veröffentlichung

Einen Multi-Plattform-Beitrag erstellen

Stelle sicher, dass dein Posting-Service auf allen gewünschten Plattformen parallel posten kann:

const createSocialPost = async (postData) => {
  const results = {};

  // Facebook Seitenbeitrag
  if (postData.platforms.includes('facebook')) {
    results.facebook = await postToFacebook({
      pageId: postData.facebookPageId,
      message: postData.message,
      link: postData.link,
      photo: postData.photo
    });
  }

  // Twitter Beitrag
  if (postData.platforms.includes('twitter')) {
    results.twitter = await postToTwitter({
      text: postData.message,
      media: postData.photo
    });
  }

  // LinkedIn Beitrag
  if (postData.platforms.includes('linkedin')) {
    results.linkedin = await postToLinkedIn({
      authorUrn: postData.linkedinAuthorUrn,
      text: postData.message,
      contentUrl: postData.link
    });
  }

  // Instagram Beitrag
  if (postData.platforms.includes('instagram')) {
    results.instagram = await postToInstagram({
      igAccountId: postData.igAccountId,
      imageUrl: postData.photo,
      caption: postData.message
    });
  }

  return results;
};
Enter fullscreen mode Exit fullscreen mode

Beispielimplementierungen für Plattformen:

// Facebook-Posting
const postToFacebook = async (postData) => {
  const token = await getFacebookPageToken(postData.pageId);

  const params = new URLSearchParams({
    message: postData.message,
    access_token: token
  });

  if (postData.link) {
    params.append('link', postData.link);
  }

  if (postData.photo) {
    params.append('photo', postData.photo);
  }

  const response = await fetch(
    `https://graph.facebook.com/v18.0/${postData.pageId}/feed?${params.toString()}`,
    { method: 'POST' }
  );

  return response.json();
};

// Twitter-Posting
const postToTwitter = async (postData) => {
  const token = await getTwitterToken();

  let mediaIds = [];
  if (postData.media) {
    // Medien zuerst hochladen
    const mediaUpload = await uploadTwitterMedia(postData.media, token);
    mediaIds = [mediaUpload.media_id_string];
  }

  const response = await fetch('https://api.twitter.com/2/tweets', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      text: postData.text,
      media: mediaIds.length > 0 ? { media_ids: mediaIds } : undefined
    })
  });

  return response.json();
};

// LinkedIn-Posting
const postToLinkedIn = async (postData) => {
  const token = await getLinkedInToken();

  const post = {
    author: postData.authorUrn,
    lifecycleState: 'PUBLISHED',
    specificContent: {
      'com.linkedin.ugc.ShareContent': {
        shareCommentary: {
          text: postData.text
        },
        shareMediaCategory: postData.contentUrl ? 'ARTICLE' : 'NONE',
        media: postData.contentUrl ? [{
          status: 'READY',
          media: postData.contentUrn,
          description: { text: postData.text }
        }] : []
      }
    },
    visibility: {
      'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC'
    }
  };

  const response = await fetch('https://api.linkedin.com/v2/ugcPosts', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
      'X-Restli-Protocol-Version': '2.0.0'
    },
    body: JSON.stringify(post)
  });

  return response.json();
};

// Instagram-Posting
const postToInstagram = async (postData) => {
  const token = await getInstagramToken();

  // Schritt 1: Mediencontainer erstellen
  const containerResponse = await fetch(
    `https://graph.facebook.com/v18.0/${postData.igAccountId}/media`,
    {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${token}` },
      body: JSON.stringify({
        image_url: postData.imageUrl,
        caption: postData.caption
      })
    }
  );

  const container = await containerResponse.json();

  // Schritt 2: Veröffentlichen
  const publishResponse = await fetch(
    `https://graph.facebook.com/v18.0/${postData.igAccountId}/media_publish`,
    {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${token}` },
      body: JSON.stringify({ creation_id: container.id })
    }
  );

  return publishResponse.json();
};
Enter fullscreen mode Exit fullscreen mode

Beiträge planen

Nutze eine Job-Warteschlange (z.B. Bull, Agenda), um Beiträge zeitgesteuert zu veröffentlichen:

const schedulePost = async (postData, scheduledTime) => {
  // In der Datenbank zur späteren Ausführung speichern
  const scheduledPost = await db.scheduledPosts.create({
    message: postData.message,
    platforms: postData.platforms,
    scheduledTime: scheduledTime,
    status: 'pending',
    media: postData.media,
    link: postData.link
  });

  // Job-Warteschlange einrichten
  await jobQueue.add('publish-social-post', {
    postId: scheduledPost.id
  }, {
    delay: scheduledTime - Date.now()
  });

  return scheduledPost;
};

// Job-Prozessor
jobQueue.process('publish-social-post', async (job) => {
  const post = await db.scheduledPosts.findById(job.data.postId);

  try {
    const result = await createSocialPost(post);

    await db.scheduledPosts.update(post.id, {
      status: 'published',
      publishedAt: new Date(),
      results: result
    });

    return result;
  } catch (error) {
    await db.scheduledPosts.update(post.id, {
      status: 'failed',
      error: error.message
    });

    throw error;
  }
});
Enter fullscreen mode Exit fullscreen mode

Analysen und Berichterstattung

Abrufen von plattformübergreifenden Analysen

Sammle und aggregiere Metriken aller relevanten Plattformen:

const getSocialAnalytics = async (accountId, dateRange) => {
  const analytics = {
    facebook: await getFacebookAnalytics(accountId.facebook, dateRange),
    twitter: await getTwitterAnalytics(accountId.twitter, dateRange),
    linkedin: await getLinkedInAnalytics(accountId.linkedin, dateRange),
    instagram: await getInstagramAnalytics(accountId.instagram, dateRange)
  };

  // Metriken aggregieren
  const totals = {
    impressions: sum(analytics, 'impressions'),
    engagement: sum(analytics, 'engagement'),
    clicks: sum(analytics, 'clicks'),
    shares: sum(analytics, 'shares'),
    comments: sum(analytics, 'comments'),
    newFollowers: sum(analytics, 'newFollowers')
  };

  return { analytics, totals };
};
Enter fullscreen mode Exit fullscreen mode

Plattformspezifische Beispiel-Implementierungen:

// Facebook Insights
const getFacebookAnalytics = async (pageId, dateRange) => {
  const token = await getFacebookPageToken(pageId);

  const metrics = [
    'page_impressions_unique',
    'page_engaged_users',
    'page_post_engagements',
    'page_clicks',
    'page_fan_adds'
  ];

  const params = new URLSearchParams({
    metric: metrics.join(','),
    since: dateRange.from,
    until: dateRange.until,
    access_token: token
  });

  const response = await fetch(
    `https://graph.facebook.com/v18.0/${pageId}/insights?${params.toString()}`
  );

  return response.json();
};

// Twitter-Analysen
const getTwitterAnalytics = async (userId, dateRange) => {
  const token = await getTwitterToken();

  const response = await fetch(
    `https://api.twitter.com/2/users/${userId}/metrics/private`,
    {
      headers: { 'Authorization': `Bearer ${token}` }
    }
  );

  return response.json();
};

// LinkedIn-Analysen
const getLinkedInAnalytics = async (organizationId, dateRange) => {
  const token = await getLinkedInToken();

  const response = await fetch(
    `https://api.linkedin.com/v2/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=${organizationId}`,
    {
      headers: { 'Authorization': `Bearer ${token}` }
    }
  );

  return response.json();
};

// Instagram Insights
const getInstagramAnalytics = async (igAccountId, dateRange) => {
  const token = await getInstagramToken();

  const metrics = [
    'impressions',
    'reach',
    'engagement',
    'profile_views',
    'follower_count'
  ];

  const params = new URLSearchParams({
    metric: metrics.join(','),
    period: 'day',
    since: dateRange.from,
    until: dateRange.until
  });

  const response = await fetch(
    `https://graph.facebook.com/v18.0/${igAccountId}/insights?${params.toString()}`,
    {
      headers: { 'Authorization': `Bearer ${token}` }
    }
  );

  return response.json();
};

function sum(analytics, metric) {
  return Object.values(analytics).reduce((total, platform) => {
    return total + (platform.data?.[metric] || 0);
  }, 0);
}
Enter fullscreen mode Exit fullscreen mode

Teammanagement

Rollenbasierte Zugriffskontrolle

Definiere Rollen und Berechtigungen für dein Teammanagement:

const TEAM_ROLES = {
  ADMIN: 'admin',
  MANAGER: 'manager',
  CONTRIBUTOR: 'contributor',
  VIEWER: 'viewer'
};

const ROLE_PERMISSIONS = {
  [TEAM_ROLES.ADMIN]: ['create', 'read', 'update', 'delete', 'manage_team', 'billing'],
  [TEAM_ROLES.MANAGER]: ['create', 'read', 'update', 'approve_posts'],
  [TEAM_ROLES.CONTRIBUTOR]: ['create', 'read'],
  [TEAM_ROLES.VIEWER]: ['read']
};

const checkPermission = (userRole, requiredPermission) => {
  const permissions = ROLE_PERMISSIONS[userRole] || [];
  return permissions.includes(requiredPermission);
};
Enter fullscreen mode Exit fullscreen mode

Ratenbegrenzung

Plattform-Ratenbegrenzungen

Plattform Limit Fenster
Facebook Graph 200 Anrufe Pro Stunde pro Benutzer
Twitter API v2 300 Tweets Pro 15 Min.
LinkedIn 100-500 Anrufe Pro Tag
Instagram 200 Anrufe Pro Stunde

Implementierung der Ratenbegrenzungsbehandlung

Nutze einen eigenen Rate-Limiter für API-Requests:

class SocialMediaRateLimiter {
  constructor() {
    this.limits = {
      facebook: { limit: 200, window: 3600000 },
      twitter: { limit: 300, window: 900000 },
      linkedin: { limit: 500, window: 86400000 },
      instagram: { limit: 200, window: 3600000 }
    };
    this.counters = {};
  }

  async request(platform, endpoint, options) {
    await this.waitForCapacity(platform);

    const response = await fetch(endpoint, options);
    this.incrementCounter(platform);

    return response;
  }

  async waitForCapacity(platform) {
    const limit = this.limits[platform];
    const counter = this.counters[platform] || { count: 0, resetTime: Date.now() };

    if (Date.now() > counter.resetTime + limit.window) {
      counter.count = 0;
      counter.resetTime = Date.now();
    }

    if (counter.count >= limit.limit) {
      const waitTime = counter.resetTime + limit.window - Date.now();
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }

    this.counters[platform] = counter;
  }

  incrementCounter(platform) {
    if (!this.counters[platform]) {
      this.counters[platform] = { count: 0, resetTime: Date.now() };
    }
    this.counters[platform].count++;
  }
}
Enter fullscreen mode Exit fullscreen mode

Checkliste für die Produktionsbereitstellung

Vor dem Go-Live:

  • [ ] OAuth 2.0 für alle Plattformen implementieren
  • [ ] Tokens sicher mit Verschlüsselung speichern
  • [ ] Automatische Token-Aktualisierung einrichten
  • [ ] Ratenbegrenzung pro Plattform implementieren
  • [ ] Umfassende Fehlerbehandlung hinzufügen
  • [ ] Protokollierung für alle API-Aufrufe einrichten
  • [ ] Beitragsgenehmigungs-Workflows erstellen
  • [ ] Inhaltsmoderation implementieren
  • [ ] Analyseaggregation einrichten
  • [ ] Backup-Posting-Mechanismen erstellen

Praktische Anwendungsfälle

Social Media Dashboard

Use Case: Marketingagentur verwaltet >50 Kundenkonten.

  • Herausforderung: Multi-Plattform-Management
  • Lösung: Zentrales Dashboard mit Multi-Plattform-Posting
  • Ergebnis: 60% Zeitersparnis, konsistente Markenpräsenz

Automatisierte Inhaltsverteilung

Use Case: Verlag automatisiert Artikel-Distribution.

  • Herausforderung: Manuelles Teilen neuer Inhalte
  • Lösung: Automatisches Posting neuer Artikel auf allen Plattformen
  • Ergebnis: Sofortige Verteilung, 3x Social-Traffic

Fazit

Auch ohne öffentliche Hootsuite API kannst du mit nativen Plattform-APIs oder spezialisierten Tools Social-Media-Management effizient automatisieren.

Key Takeaways:

  • OAuth 2.0 pro Plattform implementieren
  • Ratenlimits je Plattform berücksichtigen
  • Vereinheitlichtes Posting = plattformspezifische Endpunkte
  • Analyseaggregation für Cross-Plattform-Insights nutzen
  • Apidog vereinfacht API-Tests und Teamwork

FAQ-Bereich

Hat Hootsuite noch eine API?

Nein, Hootsuite hat die öffentliche API 2024 eingestellt. Nutze native Plattform-APIs oder Alternativen wie Buffer, Sprout Social oder Agorapulse.

Wie poste ich gleichzeitig auf mehreren Plattformen?

Implementiere OAuth für jede Plattform und nutze eine zentrale Posting-Funktion, die die jeweiligen APIs parallel anspricht.

Was sind die Ratenbegrenzungen für Social Media APIs?

Beispiel-Limits: Facebook (200/Stunde), Twitter (300/15min), LinkedIn (100-500/Tag), Instagram (200/Stunde).

Wie plane ich Beiträge?

Lege Beiträge mit scheduled_time in der Datenbank ab und nutze eine Job-Warteschlange (z.B. Bull, Agenda) für zeitgesteuertes Posting.

Kann ich Analysen von allen Plattformen erhalten?

Ja, alle Plattformen bieten Analyse-APIs. Aggregiere die Daten für umfassende plattformübergreifende Reports.

Top comments (0)