Import kosztów FB ADS do Googe Sheets, najprostsza metoda korzystania z API


W Google Scipt Apps możemy w bardzo prosty sposób rozszerzyć możliwości arkuszy kalkulacyjnych. Wystarczy przejść do edytora skryptów(Narzędzia -> Edytor skryptów), napisać potrzebną nam funkcję, zapisać i jej użyć w arkuszu. Na przykład w taką:

1
2
3
function potega(wejscie) {
  return wejscie*wejscie
}

Funkcja może mieć więcej zmiennych wejściowych i może robić z nimi (prawie) wszystko odkąd Google Apps Scripts działa w środowisku V8.

Inną ciekawostką jest, że z Graph API Faceboka możemy korzystać nie tylko za pomocą tokenów o krótkim terminie ważności uzyskiwanymi np za pomocą pełnej autoryzacji aplikacji (np. za pomocą takiej biblioteki), ale możemy też ręcznie wygenerować token, którego ważność, zamiast godziny, będzie wynosiła 60 dni, dzięki czemu możemy w mniej więcej 20-kilka linijek i kilkanaście minut przygotować szybki import danych np. z Facebook Ads do Google Sheets. Będziemy do tego potrzebowali tylko aplikacji, z niej uzyskamy token, a ten wstawimy do funkcji w Google Apps Script. Jedziemy!

Tworzymy Facebook App ID

Wchodzimy na stronę developers.facebook.com/i klikamy “Create App”. Wybieramy cel tworzenia aplikacji, w naszym przypadku jest to “Manage Business Integrations”. W następnym kroku wybieramy nazwę aplikacji (dla naszych potrzeb) wpisujemy swojego maila, wybieramy opcję, że będziemy korzystać z aplikacji dla własnych potrzeb, w razie potrzeby możemy od razu przypisać aplikację do zasobów firmowych, aby ułatwić zarządzanie nią w organizacji. Klikamy “Create App” i czekamy, aż nasza aplikacja zostanie utworzona. Ostatnią rzecz jaką musimy jeszcze zrobić to dodanie do naszej aplikacji “Marketing API”. Wystarczy kliknąć “Set Up” na korespondującym kafelku. Mamy naszą aplikację, za pomocą której będziemy autoryzować zapytania do Graph API Facebooka.

Jak działa API

Przejdźmy do Graph API Explorer. Tutaj możemy przetestować jak będą działały zapytania do API. Działa jak przeglądarka, w którą możemy wpisać odpowiednie parametry naszego zapytania i sprawdzić czy ono zadziała, oraz jaką uzyskamy odpowiedź. W bocznej części wybieramy aplikację, i klikamy “Generate Access Token”.

Teraz następuje logowanie aplikacji do zasobów przypisanych do naszego profilu. Po zalogowaniu musimy jeszcze rozszerzyć uprawnienia do read_ads, aby móc uzyskać dostęp do informacji o kontach reklamowych do których mamy odpowiednie uprawnienia.

Klikamy jeszcze raz “Generate Access Token” w pop upie zgadzamy się na przydzielenie nowych uprawnień aplikacji i już możemy działać dalej :)

Teraz potrzebujemy jeszcze numeru indentyfikatora konta reklamowego. Znajdziemy go np w Ads Managerze w górnym prawym rogu obok nazwy konta w nawiasach. Jeżeli jesteśmy zalogowani do odpowiedniego konta reklamowego znajdziemy go również w adresie strony jako wartość parametru act.

Jeżeli wszystko do tej pory przebiegało jak powinno powinniśmy móc w górny pasek wkleić taki ciąg znaków:

act_[tu wstaw id konta ads]]/insights?level=account&fields=spend&date_preset=lifetime

i uzyskać sumę wydatków na naszym koncie w domyślnej walucie. Tak jak na screenie.

Klikamy w “Get Code” i przejdźmy do sekcji “cURL”. W cudzysłowie dostaniemy adres URL z naszymi parametrami zakończony parametrem access_token wraz z wartością.

Jeżeli teraz wklejamy zawartość tego cudzysłowu do przeglądarki dostaniemy odpowiedź w postaci JSON. Więc jeżeli w panelu Google Apps Sctipt stworzymy taką funkcję:

1
2
3
4
5
6
7
8
function test(){
  const url = "[UZYSKANY Z GRAPH API EXPLORER LINK]";
// Powinien wyglądać tak:
// “https://graph.facebook.com/v8.0/act_[ID_KONTA_FB_ADS]/insights?level=account&fields=spend&date_preset=lifetime&access_token=[ACCESS_TOKEN]”
  const fetchRequest = UrlFetchApp.fetch(url);
  const results = JSON.parse(fetchRequest.getContentText());
  Logger.log(results.data[0].spend);
}

W oknie Dzienników otrzymamy interesującą nas samą sumę wydatków. (Musimy nadać skryptowi uprawnienia do wykonywania żądań do zewnętrznych aplikacji, oczywiście zgadzamy się, podobnie jak w przypadku wszystkich innych aplikacji)

Teraz jeżeli będziemy tylko odpowiednio manipulować parametrami uzyskamy interesujący nas efekt.

I tak w dużym uproszczeniu wyglądają zapytania do API Facebooka. Uprawniamy aplikację do wykonywania w naszym imieniu określonych działań, logujemy się, uwierzytelniamy i rozpoczynamy sesję dzięki temu otrzymujemy token, którym podobnie jak podpisem pod dokumentem potwierdzamy, że mamy prawo do wykonania określonej w zapytaniu czynności. Możemy cały ten proces uzyskiwania tokenu zautomatyzować np. wykorzystująć wspomnianą wcześniej bibliotekę OAuth2 for Apps Script lub uzyskać Long-Term Token by móc z niego korzystać przez dwa miesiące bez potrzeby ponownego uwierzytelniania.

Tu skorzystamy z tej drugiej metody, ponieważ jest dużo prostsza. Od momentu uzyskania Long-Term Token będziemy się posługiwać tylko jednym plikiem kodu, nie będziemy musieli tworzyć dodatkowych interface’ów, okienek, edytować manifestów. Wystarczy że poskładamy odpowiednie parametry w zapytaniu GET i obrobimy wynik. Nic nie stoi jednak na przeszkodzie aby być może w przyszłości usprawnić tę aplikację ;)

Uzyskiwanie Long-Term Token

Wróćmy do Graph API Explorera. W polu Access Token klikniemy w ikonę “i” Wyświetlą nam się podstawowe informacje na jego temat, między innymi informacja kiedy wygasa.

  1. Klikamy w “Open in Access Token Tool”
  2. W nowej karcie widzimy “Access Token Debugger” klikamy “Extend Access Token” i potwierdzamy wpisując hasło do naszego konta.
  3. Klikamy w “Debug”
  4. W nowej karcie otrzymujemy nasz ważny dwa miesiące Long-Term Token

Składamy wszystko do kupy - tworzymy funkcje Google Script Apps

Trzon naszej funkcji już zrobiliśmy wykonując pierwszy test. Podrasujemy go trochę tak aby jako argument przyjmował dzień w formacie ISO (warto posłużyć się odpowiedą metodą), z którego chcemy pozyskać statystyki oraz ciąg znaków oznaczający jaką statystykę chcemy pozyskać. Wszystkie parametry będziemy doklejać do stringa, który potem musimy zakodować, wykonać, rezultat sparsować i zwrócić interesujący nas wynik. Wszystkie parametry są dobrze opisane w dokumentacji.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const TOKEN = '[Long-Life Token]';
const FB_ADS_ID = '[id konta ADS]';

function get_fb_ads_stats(date, field){
    date = Utilities.formatDate(date, 'Europe/Warsaw', "yyyy-MM-dd");
    const dateRange = '{"since":"' + date + '","until":"' + date + '"}';
    let url = `https://graph.facebook.com/v8.0/act_${FB_ADS_ID}/insights?level=account&fields=${field}&time_range=${dateRange}&access_token=${TOKEN}`;
    url = encodeURI(url);
    const fetchRequest = UrlFetchApp.fetch(url);
    const results = JSON.parse(fetchRequest.getContentText());
    try{
    return results.data[0][field];
  } catch (e) {
    if (e instanceof TypeError){
      return 0;
    }
  }  
}

Powyższa funkcja powinna dać taki efekt:

Jeżeli widzisz w arkuszu błąd #NAME? “Nieznana funkcja…” uruchom arkusz jeszcze raz. Po odświeżeniu okna powinno być ok.

Dodatkowe parametry

Funkcję możemy rozbudowywać i rozszerzać za pomocą wraperów , aby zachować czytelność. Na przykład interesują nas tylko koszty kampani remarketingowych. Na szczęście jesteśmy konsekwentni w nazywaniu kampanii i wszystkie takie kampanie posiadają w nazwie przedrostek “[RMK]”. Aby nie powielać bez sensu tej samej funkcji dodamy do poprzedniej funkcji nieobowiązkowy parametr extra, którego wartość dodamy na końcu zmiennej url (kolejność parametrów zapytania nie ma znaczenia, więc możemy dopisywać je dowolne). Rozszerzona funkcja będzie wyglądać tak:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
function get_fb_ads_stats(date, field, extra = ''){
    date = Utilities.formatDate(date, 'Europe/Warsaw', "yyyy-MM-dd");
    const dateRange = `{"since":"${date}","until":"${date}"}`;
  let url = `https://graph.facebook.com/v8.0/act_${FB_ADS_ID}/insights?level=account&fields=${field}&time_range=${dateRange}&access_token=${TOKEN}`;
    url = url + extra;
    url = encodeURI(url);
    const fetchRequest = UrlFetchApp.fetch(url);
    const results = JSON.parse(fetchRequest.getContentText());
  try{
    return results.data[0][field];
  } catch (e) {
    if (e instanceof TypeError){
      return 0;
    }
  }  
}

Teraz aby stworzyć funkcję, która zwróci nam koszty kampani remarketingowych z danego dnia wystarczy stworzyć coś takiego:

1
2
3
4
function get_rmk_cost(date){
    const filter = '&filtering=[{field:"campaign.name",operator:"CONTAIN",value:"[RMK]"}]';
    return get_fb_ads_stats(date, 'spend', filter);
}

Należy pamiętać aby kolejne parametry rozpoczynały się od znaku & tak jak np w przypadku parametrów UTM. Warto tworzyć takie wrappery nie tylko do filtrowania, ale również jako ułatwienie w korzystaniu ze skryptu. Łatwiej uniknąć błędów wpisując w komórkę platne_klikniecia(A2) niż get_fb_ads_stats(A1; clicks), przynajmniej nie trzeba ciągle szukać w dokumentacji jak nazywają się poszczególne pola.

Dodatkowe bezpieczeństwo

Ta metoda ma tę wadę, że jeżeli token dostanie się w niepowołane ręce to nie można go unieważnić. Możemy za to zastosować dodatkową weryfikację tokenów za pomocą App Secret. Wystarczy dodać do zapytania parametr appsecret_proof, którego wartością będzie hash sha_256 z tokenu i App Secret jako klucza. Sam hash możemy wygenerować ręcznie np. na tej stronie, wynik zapisać w kodzie i dodać do każdego wychodzącego z Google Apps Script zapytania. Wymóg wynik dodatkowego uwierzytelnienia musimy włączyć w opcjach zaawansowanych naszej aplikacji w Facebooku. Więcej szczegółów w dokumentacji. Dzięki temu gdy kod skryptu dostanie się w niepowołane ręce wystarczy tylko zresetować App Secret i wygenerować nowy appsecret_proof. Możemy również po prostu usunąć aplikację z Facebooka lub zabrać jej uprawnienia.

Podsumowanie i ograniczenia

Oprócz problemów z bezpieczeństwem, które mogą spotkać każdą implementację oraz potrzeby generowania nowego tokenu co dwa miesiące taki import ma również problem z ilością generowanych zapytań. Każde API narzuca pewne ograniczenia względem ilości zapytań, Marketing API Facebooka również. Dobrą praktyką powinno być, aby łączyć zapytania w większe, np. jedno zapytanie o 1000 dni, nie 1000 pojedynczych zapytań. Poza tym jeżeli na raz wykonamy bardzo wiele requestów Facebook może po prostu uznać, że “nadużywamy jego gościnności” i kazać nam poczekać przed wykonaniem kolejnego zapytania.

Najczęstszy problem, na który trzeba uważać.

Dodatkowo Google Sheets w komórce zapisze nam formułę, a nie jej wynik. Więc włączając zapisany wcześniej arkusz z danymi wszystkie komórki wyślą ponownie zapytanie do API, a my zamiast danych zobaczymy mozaikę takich błędów. Podobnie gdy podłączymy taki arkusz np do Data Studio. Dlatego warto kopiować wynik formuły i następnie wkleić tylko jej wartość.

Nie jest to metoda idealna, ale bajecznie prosta. Nie wymaga też ogromnych umiejętności programistycznych czy dużej ilości wybiegów. Po prostu działa. Można też na jej podstawie stworzyć skrypt, który raz dziennie pobierze nam dane z facebooka na temat reklam, połączyć taki arkusz z Data Studio i niewielkim kosztem mieć w pełni funkcjonalny dashboard :)

Adam Czarnecki

Analityk internetowy, Full-Stack Marketer