├── BasicStepsFBAPI.R ├── BasicStepsFBAPI_Answers.R ├── Country_Codes.csv ├── First_Step.pdf ├── HandsOn.pdf └── README.md /BasicStepsFBAPI.R: -------------------------------------------------------------------------------- 1 | 2 | ## This code was written for the Pre-Workshop of the IUSSP Research workshop on Digital Demography in the Era 3 | ## of Big Data by Sofia Gil-Clavel. 05.06.2019. 4 | ## You can check the Markdown format of this code and more information in 5 | ## https://github.com/SofiaG1l/Using_Facebook_API 6 | 7 | #### 1. Basic URL #### 8 | # 9 | # First lets try using a browser, replace your data in the next URL: 10 | 11 | # https://graph.facebook.com/<>/act_<>/delivery_estimate?access_token=<>&include_headers=false&method=get&pretty=0&suppress_http_code=1&method=get&optimization_goal=REACH&pretty=0&suppress_http_code=1&targeting_spec={"geo_locations":{"countries":["MX"]},"genders":[1] ,"age_min":16, "age_max":24} 12 | 13 | 14 | #### 2. Retrieving in a Programmatic Way #### 15 | # 16 | # In order to retrieve and transform the data to a data frame we will use the packages **tidyverse** and **jsonlite**. 17 | 18 | # Cleaning the enviroment 19 | rm(list = ls()) 20 | gc() 21 | 22 | # Opening packages 23 | library(tidyverse) 24 | library(jsonlite) 25 | 26 | # The way we will pass our credentials to Facebook is through the string that we will save in **Credentials**, so save 27 | # your token into the variable *token* and your creation act into *act*: 28 | 29 | token="Token" 30 | 31 | act="Creation Act" 32 | 33 | version="vX.X" # replace the X with your values 34 | 35 | Credentials=paste0('https://graph.facebook.com/',version,'/act_',act,'/delivery_estimate?access_token=',token,'&include_headers=false&method=get&optimization_goal=REACH&pretty=0&suppress_http_code=1') 36 | 37 | #### 3. Total Population broken down by age, gender and country #### 38 | # 39 | # Let's set up our initial variables, they will be save in R and then we will concatenate them in a string. 40 | 41 | Age1=25 42 | Age2=55 43 | 44 | g=1 # 1:men and 2:women 45 | 46 | C='"DE"' # Country code 47 | 48 | # The parameters we will use are in a JSON(https://www.w3schools.com/js/js_json_intro.asp) format, but we will handle 49 | # them in R through a string: 50 | # 51 | # * age_min: is a value 52 | # * age_max: is a value 53 | # * genders: is an array 54 | # * geo_locations: is a JSON object where *country* is an array 55 | 56 | query <- paste0(Credentials,'& 57 | targeting_spec={ 58 | "age_min":',Age1,', 59 | "age_max":',Age2,', 60 | "genders":[',g,'], 61 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 62 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 63 | "device_platforms":["mobile","desktop"], 64 | "publisher_platforms":["facebook","messenger"], 65 | "messenger_positions":["messenger_home"]}') 66 | 67 | 68 | (query_val<-url(query)%>%fromJSON) 69 | 70 | 71 | # Since **age_min** and **age_max** are *JSON values* their input is always a single value, 72 | # in this case an integer value between 16 and 65, where 65 means *65 and over*. 73 | # 74 | # In the case of **genders**, it is an array, that means that it can receive more than one value, 75 | # but the values must be the same type (integer, float, character, etc). So, if we want to query the 76 | # number of either women or men that use Facebook, we would have to set **genders** to $[1,2]$. 77 | # 78 | # Finally, **geo_locations** is a JSON object, therefore, it can contain all the JSON objects already 79 | # described. In this case, we are specifying **countries** and **location_types** and both are arrays. 80 | # 81 | # You can find more information about these and other parameters in 82 | # https://developers.facebook.com/docs/marketing-api/targeting-specs. 83 | 84 | 85 | #### 3.1 Exercise 1 #### 86 | 87 | # Change the parameters in the code in order to retrieve the next data: 88 | # *The number of women and men between 20 and 55 years old that live in Spain and Germany and are Facebook users.* 89 | 90 | #### Your code 91 | # 92 | # 93 | # 94 | # 95 | # 96 | # 97 | # 98 | 99 | #### 4. Total Population that match certain characteristics broken down by age, gender and country #### 100 | 101 | # The first step is to know the name of all the possible variables that we can query. There are three 102 | # different classes: 103 | # * demographics 104 | # * interests 105 | # * behaviors 106 | 107 | # Let's retrieve all the *demographics* variables: 108 | 109 | library(httr) 110 | 111 | DF_CHARTICS<-GET( 112 | 113 | "https://graph.facebook.com/v3.2/search", 114 | 115 | query=list( 116 | 117 | type='adTargetingCategory', 118 | 119 | class='demographics', 120 | 121 | access_token=token, 122 | 123 | limit=2000 124 | 125 | )) %>%content(as="text")%>%fromJSON%>%.[[1]] 126 | 127 | View(DF_CHARTICS) 128 | 129 | # Now we will prepare a basic query, for this you just need to choose one variable and save the next information: 130 | 131 | ROW=1 132 | 133 | (TYPE=DF_CHARTICS$type[ROW]) 134 | (ID=DF_CHARTICS$id[ROW]) 135 | (NAME=DF_CHARTICS$name[ROW]) 136 | 137 | # For targeting populations that match specific characteristics we will use the parameter *flexible_spec* from 138 | # the Facebook Marketing API, this parameter is a JSON object. In order to incorporate it to our initial string, 139 | # we will save the string in the variable **CHARTICS**. 140 | 141 | CHARTICS<-paste0(',"flexible_spec":[{"',TYPE,'":[{"id":"',ID,'","name":"',NAME,'"}]}]') 142 | 143 | # A basic query including this parameter is: 144 | 145 | query <- paste0(Credentials,'& 146 | targeting_spec={"age_min":',Age1,', 147 | "age_max":',Age2,', 148 | "genders":[',g,']', 149 | CHARTICS,', 150 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 151 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 152 | "device_platforms":["mobile","desktop"], 153 | "publisher_platforms":["facebook","messenger"], 154 | "messenger_positions":["messenger_home"]}') 155 | 156 | 157 | (query_val<-url(query)%>%fromJSON) 158 | 159 | 160 | # In the case of the specific characteristics, you can make the next type of queries: 161 | 162 | ### * *one characteristics **and** other*: 163 | 164 | '"flexible_spec":[{ 165 | "TYPE_1":[{"id":"ID_1","name":"NAME_1"}] 166 | }, 167 | { 168 | "TYPE_2":[{"id":"ID_2","name":"NAME_2"}] 169 | }]' 170 | 171 | ### * *one characteristics **or** other*: 172 | 173 | '"flexible_spec":[{ 174 | "TYPE_1":[{"id":"ID_1","name":"NAME_1"}], 175 | "TYPE_2":[{"id":"ID_2","name":"NAME_2"}] 176 | }]' 177 | 178 | # In the case of OR we need to group by TYPE. Check the next example: 179 | # *People that are travelers **OR** like soccer **OR** movies.* 180 | 181 | '"flexible_spec": [{ 182 | "behaviors": [ 183 | {"id":6002714895372,"name":"All travelers"} 184 | ], 185 | "interests": [ 186 | {"id":6003107902433,"name":"Association football (Soccer)"}, 187 | {"id":6003139266461,"name":"Movies"} 188 | ] 189 | }]' 190 | 191 | # More info here: https://developers.facebook.com/docs/marketing-api/targeting-specs#broadcategories 192 | 193 | #### 4.1 Exercise 2 #### 194 | 195 | # Code the next query: 196 | # *The number of women between 50 and 60 years old that live in Spain that 197 | # are "Away from hometown" and "Close friends of people with birthdays in a month" and are Facebook users.* 198 | 199 | #### Your code: 200 | # 201 | # 202 | # 203 | # 204 | # 205 | 206 | #### 4.1 Exercise 3 #### 207 | 208 | # Code the next query: 209 | # *The number of women between 50 and 60 years old that live in Spain that 210 | # are either "Away from hometown" or "Close friends of people with birthdays in a month" and are Facebook users.* 211 | 212 | #### Your code: 213 | # 214 | # 215 | # 216 | # 217 | # 218 | 219 | 220 | #### So Far, So Good? #### 221 | 222 | # Let's challenge your understanding on retrieving data. In the next steps you will recreate part of the code that was 223 | # used for the paper Demographic Diferentials in Facebook Usage Around the World, but just for some of the countries 224 | # in Country_Codes.csv. 225 | 226 | 227 | #### **Exercise: Basic Demographic Information** #### 228 | # 229 | # 1. Upload Country_Codes.csv into the R environment. 230 | # 2. Create a data frame where you will save all the information. 231 | # 3. Create a nest loop where you can change the next variables in your queries: 232 | # Country: each country in Country_Codes.csv. 233 | # Age: 16-24, 25-54, 55-64 234 | # Gender: female and male 235 | # 236 | #### Your code: 237 | # 238 | # 239 | # 240 | # 241 | # 242 | # If you already have the steps 1 to 3, then you will notice a problem. What problem are you encountering? 243 | 244 | 245 | #### **Exercise: Specific Characteristics** #### 246 | # 247 | # Now we are going to restrict the population to those that match specific characteristics: 248 | # Away from hometown 249 | # Close friend of users with birthdays in a month 250 | # 251 | #### Your code: 252 | # 253 | # 254 | # 255 | # 256 | # 257 | 258 | # **The Solutions** 259 | # 260 | # You can find the complete code for replicating the 261 | # [*Demographic Diferentials in Facebook Usage Around the World*](https://arxiv.org/abs/1905.09105 "Demographic Diferentials in Facebook Usage Around the World") 262 | # [here](https://github.com/SofiaG1l/Using_Facebook_API/blob/master/BasicStepsFBAPI_Answers.R "Solutions"). 263 | # 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | -------------------------------------------------------------------------------- /BasicStepsFBAPI_Answers.R: -------------------------------------------------------------------------------- 1 | 2 | ## This code was written for the Pre-Workshop of the IUSSP Research workshop on Digital Demography in the Era 3 | ## of Big Data by Sofia Gil-Clavel. 05.06.2019. 4 | ## You can check the Markdown format of this code and more information in 5 | ## https://github.com/SofiaG1l/Using_Facebook_API 6 | 7 | #### 1. Basic URL #### 8 | # 9 | # First lets try using a browser, replace your data in the next URL: 10 | 11 | # https://graph.facebook.com/<>/act_<>/delivery_estimate?access_token=<>&include_headers=false&method=get&pretty=0&suppress_http_code=1&method=get&optimization_goal=REACH&pretty=0&suppress_http_code=1&targeting_spec={"geo_locations":{"countries":["MX"]},"genders":[1] ,"age_min":16, "age_max":24} 12 | 13 | 14 | #### 2. Retrieving in a Programmatic Way #### 15 | # 16 | # In order to retrieve and transform the data to a data frame we will use the packages **tidyverse** and **jsonlite**. 17 | 18 | rm(list=ls()) 19 | gc() 20 | 21 | library(tidyverse) 22 | library(jsonlite) 23 | 24 | # The way we will pass our credentials to Facebook is through the string that we will save in **Credentials**, so save 25 | # your token into the variable *token* and your creation act into *act*: 26 | 27 | token="Your Token" 28 | 29 | act="Your Creation Act" 30 | 31 | version="vX.X" # Change the Xs with your version and delete <<>> 32 | 33 | Credentials=paste0('https://graph.facebook.com/',version,'/act_',act,'/delivery_estimate?access_token=',token,'&include_headers=false&method=get&optimization_goal=REACH&pretty=0&suppress_http_code=1') 34 | 35 | #### 3. Total Population broken down by age, gender and country #### 36 | # 37 | # Let's set up our initial variables, they will be save in R and then we will concatenate them in a string. 38 | 39 | Age1=25 40 | Age2=55 41 | 42 | g=1 # 1:men and 2:women 43 | 44 | C='"DE"' # Country code 45 | 46 | # The parameters we will use are in a JSON(https://www.w3schools.com/js/js_json_intro.asp) format, but we will handle 47 | # them in R through a string: 48 | # 49 | # * age_min: is a value 50 | # * age_max: is a value 51 | # * genders: is an array 52 | # * geo_locations: is a JSON object where *country* is an array 53 | 54 | query <- paste0(Credentials,'& 55 | targeting_spec={ 56 | "age_min":',Age1,', 57 | "age_max":',Age2,', 58 | "genders":[',g,'], 59 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 60 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 61 | "device_platforms":["mobile","desktop"], 62 | "publisher_platforms":["facebook","messenger"], 63 | "messenger_positions":["messenger_home"]}') 64 | 65 | 66 | (query_val<-url(query)%>%fromJSON) 67 | 68 | query_val$data['estimate_dau'][[1]] 69 | query_val$data['estimate_mau'][[1]] 70 | 71 | 72 | # Since **age_min** and **age_max** are *JSON values* their input is always a single value, 73 | # in this case an integer value between 16 and 65, where 65 means *65 and over*. 74 | # 75 | # In the case of **genders**, it is an array, that means that it can receive more than one value, 76 | # but the values must be the same type (integer, float, character, etc). So, if we want to query the 77 | # number of either women or men that use Facebook, we would have to set **genders** to $[1,2]$. 78 | # 79 | # Finally, **geo_locations** is a JSON object, therefore, it can contain all the JSON objects already 80 | # described. In this case, we are specifying **countries** and **location_types** and both are arrays. 81 | # 82 | # You can find more information about these and other parameters in 83 | # https://developers.facebook.com/docs/marketing-api/targeting-specs. 84 | 85 | 86 | #### 3.1 Exercise 1 #### 87 | 88 | # Change the parameters in the code in order to retrieve the next data: 89 | # *The number of women and men between 20 and 55 years old that live in Spain and Germany and are Facebook users.* 90 | 91 | #### Your code 92 | Age1=20 93 | Age2=55 94 | g="1,2" 95 | C='"ES","DE"' 96 | 97 | query <- paste0(Credentials,'& 98 | targeting_spec={ 99 | "age_min":',Age1,', 100 | "age_max":',Age2,', 101 | "genders":[',g,'], 102 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 103 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 104 | "device_platforms":["mobile","desktop"], 105 | "publisher_platforms":["facebook","messenger"], 106 | "messenger_positions":["messenger_home"]}') 107 | 108 | (query_val<-url(query)%>%fromJSON) 109 | 110 | query_val$data['estimate_dau'][[1]] 111 | query_val$data['estimate_mau'][[1]] 112 | 113 | #### 4. Total Population that match certain characteristics broken down by age, gender and country #### 114 | 115 | # The first step is to know the name of all the possible variables that we can query. There are three 116 | # different classes: 117 | # * demographics 118 | # * interests 119 | # * behaviors 120 | 121 | # Let's retrieve all the *demographics* variables: 122 | 123 | library(httr) 124 | 125 | DF_CHARTICS<-GET( 126 | 127 | "https://graph.facebook.com/<>/search", # Change the Xs with your version and delete <<>> 128 | 129 | query=list( 130 | 131 | type='adTargetingCategory', 132 | 133 | class='demographics', 134 | 135 | access_token=token, 136 | 137 | limit=2000 138 | 139 | )) %>%content(as="text")%>%fromJSON%>%.[[1]] 140 | 141 | View(DF_CHARTICS) 142 | 143 | # Now we will prepare a basic query, for this you just need to choose one variable and save the next information: 144 | 145 | ROW=1 146 | 147 | (TYPE=DF_CHARTICS$type[ROW]) 148 | (ID=DF_CHARTICS$id[ROW]) 149 | (NAME=DF_CHARTICS$name[ROW]) 150 | 151 | # For targeting populations that match specific characteristics we will use the parameter *flexible_spec* from 152 | # the Facebook Marketing API, this parameter is a JSON object. In order to incorporate it to our initial string, 153 | # we will save the string in the variable **CHARTICS**. 154 | 155 | CHARTICS<-paste0(',"flexible_spec":[{"',TYPE,'":[{"id":"',ID,'","name":"',NAME,'"}]}]') 156 | 157 | # A basic query including this parameter is: 158 | 159 | query <- paste0(Credentials,'& 160 | targeting_spec={"age_min":',Age1,', 161 | "age_max":',Age2,', 162 | "genders":[',g,']', 163 | CHARTICS,', 164 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 165 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 166 | "device_platforms":["mobile","desktop"], 167 | "publisher_platforms":["facebook","messenger"], 168 | "messenger_positions":["messenger_home"]}') 169 | 170 | 171 | (query_val<-url(query)%>%fromJSON) 172 | 173 | query_val$data['estimate_dau'][[1]] 174 | query_val$data['estimate_mau'][[1]] 175 | 176 | 177 | # In the case of the specific characteristics, you can make the next type of queries: 178 | 179 | #* *one characteristics **and** other*: 180 | 181 | '"flexible_spec":[{ 182 | "TYPE_1":[{"id":"ID_1","name":"NAME_1"}] 183 | }, 184 | { 185 | "TYPE_2":[{"id":"ID_2","name":"NAME_2"}] 186 | }]' 187 | 188 | # * *one characteristics **or** other*: 189 | 190 | '"flexible_spec":[{ 191 | "TYPE_1":[{"id":"ID_1","name":"NAME_1"}], 192 | "TYPE_2":[{"id":"ID_2","name":"NAME_2"}] 193 | }]' 194 | 195 | # In the case of OR we need to group by TYPE. Check the next example: 196 | # *People that are travelers OR like soccer OR movies.* 197 | 198 | '"flexible_spec": [{ 199 | "behaviors": [ 200 | {"id":6002714895372,"name":"All travelers"} 201 | ], 202 | "interests": [ 203 | {"id":6003107902433,"name":"Association football (Soccer)"}, 204 | {"id":6003139266461,"name":"Movies"} 205 | ] 206 | }]' 207 | 208 | # More info here: https://developers.facebook.com/docs/marketing-api/targeting-specs#broadcategories 209 | 210 | #### 4.1 Exercise 2 #### 211 | 212 | # Code the next query: 213 | # *The number of women between 50 and 60 years old that live in Spain that 214 | # are "Away from hometown" and "Close friends of people with birthdays in a month" and are Facebook users.* 215 | 216 | #### Your code: 217 | 218 | Age1=50 219 | Age2=60 220 | g="2" 221 | C='"ES"' 222 | 223 | # Checking where the variables are and save their info: 224 | 225 | ROW=which(DF_CHARTICS$name=="Away from hometown") 226 | 227 | (TYPE_1=DF_CHARTICS$type[ROW]) 228 | (ID_1=DF_CHARTICS$id[ROW]) 229 | (NAME_1=DF_CHARTICS$name[ROW]) 230 | 231 | ROW=which(DF_CHARTICS$name=="Close friends of people with birthdays in a month") 232 | 233 | (TYPE_2=DF_CHARTICS$type[ROW]) 234 | (ID_2=DF_CHARTICS$id[ROW]) 235 | (NAME_2=DF_CHARTICS$name[ROW]) 236 | 237 | # Preparing string of characteristics: 238 | CHARTICS<-paste0(',"flexible_spec":[{"',TYPE_1,'":[{"id":"',ID_1,'","name":"',NAME_1,'"}]}, 239 | {"',TYPE_2,'":[{"id":"',ID_2,'","name":"',NAME_2,'"}]}]') 240 | 241 | # Preparing query: 242 | query <- paste0(Credentials,'& 243 | targeting_spec={"age_min":',Age1,', 244 | "age_max":',Age2,', 245 | "genders":[',g,']', 246 | CHARTICS,', 247 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 248 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 249 | "device_platforms":["mobile","desktop"], 250 | "publisher_platforms":["facebook","messenger"], 251 | "messenger_positions":["messenger_home"]}') 252 | 253 | # Retrieving: 254 | (queryAND_val<-url(query)%>%fromJSON) 255 | 256 | queryAND_val$data['estimate_dau'][[1]] 257 | queryAND_val$data['estimate_mau'][[1]] 258 | 259 | 260 | #### 4.1 Exercise 3 #### 261 | 262 | # Code the next query: 263 | # *The number of women between 50 and 60 years old that live in Spain that 264 | # are either "Away from hometown" or "Close friends of people with birthdays in a month" and are Facebook users.* 265 | 266 | #### Your code 267 | 268 | # Preparing string of characteristics: 269 | CHARTICS<-paste0(',"flexible_spec":[{"',TYPE_1,'":[{"id":"',ID_1,'","name":"',NAME_1,'"},{"id":"',ID_2,'","name":"',NAME_2,'"}]}]') 270 | 271 | # Preparing query: 272 | query <- paste0(Credentials,'& 273 | targeting_spec={"age_min":',Age1,', 274 | "age_max":',Age2,', 275 | "genders":[',g,']', 276 | CHARTICS,', 277 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 278 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 279 | "device_platforms":["mobile","desktop"], 280 | "publisher_platforms":["facebook","messenger"], 281 | "messenger_positions":["messenger_home"]}') 282 | 283 | # Retrieving: 284 | (queryOR_val<-url(query)%>%fromJSON) 285 | 286 | queryOR_val$data['estimate_dau'][[1]] 287 | queryOR_val$data['estimate_mau'][[1]] 288 | 289 | 290 | 291 | #### So Far, So Good? #### 292 | 293 | # Let's challenge your understanding on retrieving data. In the next steps you will recreate part of the code that was 294 | # used for the paper Demographic Diferentials in Facebook Usage Around the World, but just for some of the countries 295 | # in Country_Codes.csv. 296 | 297 | 298 | # **Basic Demographic Information** 299 | # 300 | # 1. Upload Country_Codes.csv into the R environment. 301 | # 2. Create a data frame where you will save all the information. 302 | # 3. Create a nest loop where you can change the next variables in your queries: 303 | # Country: each country in Country_Codes.csv. 304 | # Age: 16-24, 25-54, 55-64 305 | # Gender: female and male 306 | 307 | # 1. Upload Country_Codes.csv into the R environment. 308 | 309 | setwd("Path to the Data base") 310 | 311 | Country_Codes<-read.csv("Country_Codes.csv",stringsAsFactors = FALSE) 312 | 313 | # 2. Create a data frame where you will save all the information. 314 | total=nrow(Country_Codes)*2*3 # nrow(Country_Codes): number of countries, 2 genders, 3 ages group 315 | DB<-data.frame("CODE"=rep(0,total)) 316 | DB$GENDER=0 317 | DB$AGE1=0 318 | DB$AGE2=0 319 | DB$estimate_dau=0 320 | DB$estimate_mau=0 321 | DB$estimate_ready=0 322 | 323 | # 3. Create a nest loop where you can change the next variables in your queries: 324 | 325 | CODE=Country_Codes$alpha.2 326 | AGE=list(c(16,24),c(25,54),c(55,65)) 327 | SEX=c(1,2) 328 | 329 | i=1 330 | print(total) 331 | for(c in CODE){ 332 | for(a in AGE){ 333 | for(s in SEX){ 334 | 335 | query <- paste0(Credentials,'& 336 | targeting_spec={ 337 | "age_min":',a[1],', 338 | "age_max":',a[2],', 339 | "genders":[',s,'], 340 | "geo_locations":{"countries":["',c,'"],"location_types":["home"]}, 341 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 342 | "device_platforms":["mobile","desktop"], 343 | "publisher_platforms":["facebook","messenger"], 344 | "messenger_positions":["messenger_home"]}') 345 | 346 | # Retrieving: 347 | query_val<-url(query)%>%fromJSON 348 | 349 | DB$CODE[i]=c 350 | DB$GENDER[i]=s 351 | DB$AGE1[i]=a[1] 352 | DB$AGE2[i]=a[2] 353 | DB$estimate_dau[i]=query_val$data['estimate_dau'][[1]] 354 | DB$estimate_mau[i]=query_val$data['estimate_mau'][[1]] 355 | DB$estimate_ready[i]=ifelse(query_val$data['estimate_ready'][[1]]==1,"TRUE","FALSE") 356 | 357 | # Pause for 5 seconds 358 | Sys.sleep(5) 359 | print(paste("Processed:",round(100*i/total,digits = 2),"%")) 360 | i=i+1 361 | } 362 | } 363 | } 364 | 365 | View(DB) 366 | 367 | 368 | # If you already have the steps 1 to 3, then you will notice a problem. What problem are you encountering? 369 | 370 | # That you have to wait for 5 seonds before starting the next iteration 371 | Sys.sleep(5) 372 | 373 | 374 | # **Specific Characteristics** 375 | # 376 | # Now we are going to restrict the population to those that match specific characteristics: 377 | # Away from hometown 378 | # Close friend of users with birthdays in a month 379 | 380 | total=nrow(Country_Codes)*2*3*2 # nrow(Country_Codes): number of countries, 2 genders, 3 ages group, 2 specific caracteristics 381 | DB<-data.frame("CODE"=rep(0,total)) 382 | DB$GENDER=0 383 | DB$AGE1=0 384 | DB$AGE2=0 385 | DB$VARIABLE=0 386 | DB$estimate_dau=0 387 | DB$estimate_mau=0 388 | DB$estimate_ready=0 389 | 390 | CODE=Country_Codes$alpha.2 391 | AGE=list(c(16,24),c(25,54),c(55,65)) 392 | SEX=c(1,2) 393 | # The variables 394 | VARIABLES=DF_CHARTICS[DF_CHARTICS$name%in%c("Away from hometown","Close friends of people with birthdays in a month"),] 395 | 396 | 397 | i=1 398 | print(total) 399 | for(c in CODE){ 400 | for(v in 1:nrow(VARIABLES)){ 401 | for(a in AGE){ 402 | for(s in SEX){ 403 | 404 | CHARTICS<-paste0(',"flexible_spec":[{"',VARIABLES$type[v],'":[{"id":"',VARIABLES$id[v],'","name":"',VARIABLES$name[v],'"}]}]') 405 | 406 | # A basic query including this parameter is: 407 | 408 | query <- paste0(Credentials,'& 409 | targeting_spec={"age_min":',a[1],', 410 | "age_max":',a[2],', 411 | "genders":[',s,']', 412 | CHARTICS,', 413 | "geo_locations":{"countries":["',c,'"],"location_types":["home"]}, 414 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 415 | "device_platforms":["mobile","desktop"], 416 | "publisher_platforms":["facebook","messenger"], 417 | "messenger_positions":["messenger_home"]}') 418 | 419 | # Retrieving: 420 | query_val<-url(query)%>%fromJSON 421 | 422 | DB$CODE[i]=c 423 | DB$GENDER[i]=s 424 | DB$AGE1[i]=a[1] 425 | DB$AGE2[i]=a[2] 426 | DB$VARIABLE[i]=VARIABLES$name[v] 427 | DB$estimate_dau[i]=query_val$data['estimate_dau'][[1]] 428 | DB$estimate_mau[i]=query_val$data['estimate_mau'][[1]] 429 | DB$estimate_ready[i]=ifelse(query_val$data['estimate_ready'][[1]]==1,"TRUE","FALSE") 430 | 431 | # Pause for 5 seconds 432 | Sys.sleep(5) 433 | 434 | print(paste("Processed:",round(100*i/total,digits = 2),"%")) 435 | i=i+1 436 | } 437 | } 438 | } 439 | } 440 | 441 | View(DB) 442 | 443 | 444 | -------------------------------------------------------------------------------- /Country_Codes.csv: -------------------------------------------------------------------------------- 1 | NAME,alpha-2,alpha-3,country-code,iso_3166-2,alpha-2,region,sub-region 2 | Austria,AT,AUT,40,ISO 3166-2:AT,AT,Europe,Western Europe 3 | Belgium,BE,BEL,56,ISO 3166-2:BE,BE,Europe,Western Europe 4 | Bulgaria,BG,BGR,100,ISO 3166-2:BG,BG,Europe,Eastern Europe 5 | Croatia,HR,HRV,191,ISO 3166-2:HR,HR,Europe,Southern Europe 6 | Czechia,CZ,CZE,203,ISO 3166-2:CZ,CZ,Europe,Eastern Europe 7 | Denmark,DK,DNK,208,ISO 3166-2:DK,DK,Europe,Northern Europe 8 | Estonia,EE,EST,233,ISO 3166-2:EE,EE,Europe,Northern Europe 9 | Finland,FI,FIN,246,ISO 3166-2:FI,FI,Europe,Northern Europe 10 | France,FR,FRA,250,ISO 3166-2:FR,FR,Europe,Western Europe 11 | Germany,DE,DEU,276,ISO 3166-2:DE,DE,Europe,Western Europe 12 | Greece,GR,GRC,300,ISO 3166-2:GR,GR,Europe,Southern Europe 13 | Hungary,HU,HUN,348,ISO 3166-2:HU,HU,Europe,Eastern Europe 14 | Ireland,IE,IRL,372,ISO 3166-2:IE,IE,Europe,Northern Europe 15 | Italy,IT,ITA,380,ISO 3166-2:IT,IT,Europe,Southern Europe 16 | Latvia,LV,LVA,428,ISO 3166-2:LV,LV,Europe,Northern Europe 17 | Lithuania,LT,LTU,440,ISO 3166-2:LT,LT,Europe,Northern Europe 18 | Luxembourg,LU,LUX,442,ISO 3166-2:LU,LU,Europe,Western Europe 19 | Malta,MT,MLT,470,ISO 3166-2:MT,MT,Europe,Southern Europe 20 | Netherlands,NL,NLD,528,ISO 3166-2:NL,NL,Europe,Western Europe 21 | Poland,PL,POL,616,ISO 3166-2:PL,PL,Europe,Eastern Europe 22 | Portugal,PT,PRT,620,ISO 3166-2:PT,PT,Europe,Southern Europe 23 | Romania,RO,ROU,642,ISO 3166-2:RO,RO,Europe,Eastern Europe 24 | Slovakia,SK,SVK,703,ISO 3166-2:SK,SK,Europe,Eastern Europe 25 | Slovenia,SI,SVN,705,ISO 3166-2:SI,SI,Europe,Southern Europe 26 | Spain,ES,ESP,724,ISO 3166-2:ES,ES,Europe,Southern Europe 27 | Sweden,SE,SWE,752,ISO 3166-2:SE,SE,Europe,Northern Europe 28 | United Kingdom of Great Britain and Northern Ireland,GB,GBR,826,ISO 3166-2:GB,GB,Europe,Northern Europe 29 | -------------------------------------------------------------------------------- /First_Step.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SofiaG1l/Using_Facebook_API/0f98dce86ba578812021017d9bb7c1127e915e8b/First_Step.pdf -------------------------------------------------------------------------------- /HandsOn.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SofiaG1l/Using_Facebook_API/0f98dce86ba578812021017d9bb7c1127e915e8b/HandsOn.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Using the Facebook Marketing API 2 | ================ 3 | Sofia Gil 4 | May 20, 2019 5 | 6 | - [Requirements](#requirements) 7 | - [Retrieving Data](#retrieving-data) 8 | - [1. Basic URL](#basic-url) 9 | - [2. Retrieving in a Programmatic Way](#retrieving-in-a-programmatic-way) 10 | - [3. Total Population broken down by age, gender and country](#total-population-broken-down-by-age-gender-and-country) 11 | - [4. Total Population that match certain characteristics broken down by age, gender and country](#total-population-that-match-certain-characteristics-broken-down-by-age-gender-and-country) 12 | - [So Far, So Good?](#so-far-so-good) 13 | - [Basic Demographic Information](#basic-demographic-information) 14 | - [Specific Characteristics](#specific-characteristics) 15 | - [The Solutions](#the-solutions) 16 | 17 | **The aim of this course** is to give a quick overview on what it is and how to use the Facebook Marketing API. In this course you will learn how to query and retrieve aggregated data regarding different users' demographic characteristics. 18 | 19 | Requirements 20 | ============ 21 | 22 | 1. Have a Facebook account 23 | 2. Set up a Facebook Marketing App 24 | 3. Obtain the Token and Creation Act of your Facebook Marketing App 25 | 4. Check the version of the API that you are using 26 | 5. Install the next R packages: 27 | - tidyverse 28 | - jsonlite 29 | - httr 30 | 6. Knowledge of R 31 | 32 | For the steps 1 to 4 you can check [**First\_Step.pdf**](https://github.com/SofiaG1l/Using_Facebook_API/blob/master/First_Step.pdf "First Step"), once you have them save them in a txt, we will be using that information for accessing the Facebook API. 33 | 34 | If you are not a R user, you can find a python tutorial [**here**](https://github.com/carolcoimbra/facebook-ads "facebook-ads"). 35 | 36 | Retrieving Data 37 | =============== 38 | 39 | Would you like to check more information about the Facebook Marketing API or about the JSON syntax? Then take a look on [**HandsOn.pdf**](https://github.com/SofiaG1l/Using_Facebook_API/blob/master/HandsOn.pdf "Hands On"). 40 | 41 | 1. Basic URL 42 | ------------ 43 | 44 | First lets try using a browser, replace your data in the next URL: 45 | 46 | ``` r 47 | https://graph.facebook.com/<>/act_<>/delivery_estimate?access_token=<>&include_headers=false&method=get&pretty=0&suppress_http_code=1&method=get&optimization_goal=REACH&pretty=0&suppress_http_code=1&targeting_spec={"geo_locations":{"countries":["MX"]},"genders":[1] ,"age_min":16, "age_max":24} 48 | ``` 49 | 50 | 2. Retrieving in a Programmatic Way 51 | ----------------------------------- 52 | 53 | In order to retrieve and transform the data to a data frame we will use the packages **tidyverse** and **jsonlite**. 54 | 55 | ``` r 56 | library(tidyverse) 57 | library(jsonlite) 58 | ``` 59 | 60 | The way we will pass our credentials to Facebook is through the string that we will save in **Credentials**, so save your token into the variable *token* and your creation act into *act*: 61 | 62 | ``` r 63 | token="Your Token" 64 | 65 | act="Your Creation Act" 66 | 67 | version="vX.X" # replace the X with your values 68 | 69 | Credentials=paste0('https://graph.facebook.com/',version,'/act_',act,'/delivery_estimate?access_token=',token,'&include_headers=false&method=get&optimization_goal=REACH&pretty=0&suppress_http_code=1') 70 | ``` 71 | 72 | 3. Total Population broken down by age, gender and country 73 | ---------------------------------------------------------- 74 | 75 | Let's set up our initial variables, they will be save in R and then we will concatenate them in a string. 76 | 77 | ``` r 78 | Age1=25 79 | Age2=55 80 | 81 | g=1 # 1:men and 2:women 82 | 83 | C='"DE"' # Country code 84 | ``` 85 | 86 | The parameters we will use are in a [JSON](https://www.w3schools.com/js/js_json_intro.asp "JSON") format, but we will handle them in R through a string: 87 | 88 | - age\_min: is a value 89 | - age\_max: is a value 90 | - genders: is an array 91 | - geo\_locations: is a JSON object where *country* is an array 92 | 93 | ``` r 94 | query <- paste0(Credentials,'& 95 | targeting_spec={ 96 | "age_min":',Age1,', 97 | "age_max":',Age2,', 98 | "genders":[',g,'], 99 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 100 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 101 | "device_platforms":["mobile","desktop"], 102 | "publisher_platforms":["facebook","messenger"], 103 | "messenger_positions":["messenger_home"]}') 104 | 105 | 106 | (query_val<-url(query)%>%fromJSON) 107 | ``` 108 | 109 | Since **age\_min** and **age\_max** are *JSON values* their input is always a single value, in this case a integer value between 16 and 65, where 65 means *65 and over*. 110 | 111 | In the case of **genders**, it is an array, that means that it can receive more than one value, but the values must be the same type (integer, float, character, etc). So, if we want to query the number of women and men that use Facebook, we would have to set **genders** to \[1, 2\]. 112 | 113 | Finally, **geo\_locations** is a JSON object, therefore, it can contain all the JSON objects already described. In this case, we are specifying **countries** and **location\_types** and both are arrays. 114 | 115 | You can find more information about these and other parameters [here](https://developers.facebook.com/docs/marketing-api/targeting-specs "Advanced Targeting and Placement"). 116 | 117 | ### 3.1 Exercise 118 | 119 | Change the parameters in the code in order to retrieve the next data: 120 | 121 | *The number of women and men between 20 and 55 years old that live in Spain and Germany and are Facebook users.* 122 | 123 | 4. Total Population that match certain characteristics broken down by age, gender and country 124 | --------------------------------------------------------------------------------------------- 125 | 126 | The first step is to know the name of all the possible variables that we can query. There are three different classes: 127 | 128 | - demographics 129 | - interests 130 | - behaviors 131 | 132 | Let's retrieve all the *demographics* variables: 133 | 134 | ``` r 135 | library(httr) 136 | 137 | DF_CHARTICS<-GET( 138 | 139 | "https://graph.facebook.com/v3.2/search", 140 | 141 | query=list( 142 | 143 | type='adTargetingCategory', 144 | 145 | class='demographics', 146 | 147 | access_token=token, 148 | 149 | limit=2000 150 | 151 | )) %>%content(as="text")%>%fromJSON%>%.[[1]] 152 | 153 | View(DF_CHARTICS) 154 | ``` 155 | 156 | Now we will prepare a basic query, for this you just need to choose one variable and save the next information: 157 | 158 | ``` r 159 | ROW=1 160 | 161 | (TYPE=DF_CHARTICS$type[ROW]) 162 | (ID=DF_CHARTICS$id[ROW]) 163 | (NAME=DF_CHARTICS$name[ROW]) 164 | ``` 165 | 166 | For targeting populations that match specific characteristics we will use the parameter *flexible\_spec* from the Facebook Marketing API, this parameter is a JSON object. In order to incorporate it to our initial string, we will save the string in the variable **CHARTICS**. 167 | 168 | ``` r 169 | CHARTICS<-paste0(',"flexible_spec":[{"',TYPE,'":[{"id":"',ID,'","name":"',NAME,'"}]}]') 170 | ``` 171 | 172 | A basic query including this parameter is: 173 | 174 | ``` r 175 | query <- paste0(Credentials,'& 176 | targeting_spec={"age_min":',Age1,', 177 | "age_max":',Age2,', 178 | "genders":[',g,']', 179 | CHARTICS,', 180 | "geo_locations":{"countries":[',C,'],"location_types":["home"]}, 181 | "facebook_positions":["feed","instant_article","instream_video","marketplace"], 182 | "device_platforms":["mobile","desktop"], 183 | "publisher_platforms":["facebook","messenger"], 184 | "messenger_positions":["messenger_home"]}') 185 | 186 | 187 | (query_val<-url(query)%>%fromJSON) 188 | ``` 189 | 190 | In the case of the specific characteristics, you can make the next type of queries: 191 | 192 | - *one characteristics **and** other*: 193 | 194 | ``` r 195 | '"flexible_spec":[{ 196 | "TYPE_1":[{"id":"ID_1","name":"NAME_1"}] 197 | }, 198 | { 199 | "TYPE_2":[{"id":"ID_2","name":"NAME_2"}] 200 | }]' 201 | ``` 202 | 203 | - *one characteristics **or** other*: 204 | 205 | ``` r 206 | '"flexible_spec":[{ 207 | "TYPE_1":[{"id":"ID_1","name":"NAME_1"}], 208 | "TYPE_2":[{"id":"ID_2","name":"NAME_2"}] 209 | }]' 210 | ``` 211 | 212 | In the case of OR we need to group by TYPE. Check the next example: *People that are travelers **OR** like soccer **OR** movies.* 213 | 214 | ``` r 215 | '"flexible_spec": [{ 216 | "behaviors": [ 217 | {"id":6002714895372,"name":"All travelers"} 218 | ], 219 | "interests": [ 220 | {"id":6003107902433,"name":"Association football (Soccer)"}, 221 | {"id":6003139266461,"name":"Movies"} 222 | ] 223 | }]' 224 | ``` 225 | 226 | More info here: 227 | 228 | ### 4.1 Exercise 2 229 | 230 | Code the next query: *The number of women between 50 and 60 years old that live in Spain that are "Away from hometown" and "Close friends of people with birthdays in a month" and are Facebook users.* 231 | 232 | ### 4.1 Exercise 3 233 | 234 | Code the next query: *The number of women between 50 and 60 years old that live in Spain that are either "Away from hometown" or "Close friends of people with birthdays in a month" and are Facebook users.* 235 | 236 | So Far, So Good? 237 | ================ 238 | 239 | Let's challenge your understanding on retrieving data. In the next steps you will recreate part of the code that was used for the paper [*Demographic Diferentials in Facebook Usage Around the World*](https://aaai.org/ojs/index.php/ICWSM/article/view/3263 "Demographic Diferentials in Facebook Usage Around the World"), but just for some of the countries in *Country\_Codes.csv*. 240 | 241 | Basic Demographic Information 242 | ----------------------------- 243 | 244 | 1. Upload *Country\_Codes.csv* into the R environment. 245 | 2. Create a data frame where you will save all the information. 246 | 3. Create a nest loop where you can change the next variables in your queries: 247 | - Country: each country in *Country\_Codes.csv*. 248 | - Age: 16-24, 25-54, 55-64 249 | - Gender: female and male 250 | 251 | If you already have the steps 1 to 3, then you will notice a problem. What problem are you encountering? 252 | 253 | Specific Characteristics 254 | ------------------------ 255 | 256 | Now we are going to restrict the population to those that match specific characteristics: 257 | 258 | - Away from hometown 259 | - Close friend of users with birthdays in a month 260 | 261 | The Solutions 262 | ------------- 263 | 264 | You can find the complete code for replicating the [*Demographic Diferentials in Facebook Usage Around the World*](https://aaai.org/ojs/index.php/ICWSM/article/view/3263 "Demographic Diferentials in Facebook Usage Around the World") [here](https://github.com/SofiaG1l/Using_Facebook_API/blob/master/BasicStepsFBAPI_Answers.R "Solutions"). 265 | 266 | --------------------------------------------------------------------------------