├── .gitignore ├── media ├── heading.PNG └── output.PNG ├── src ├── FacebookAds16.png ├── FacebookAds20.png ├── FacebookAds24.png ├── FacebookAds32.png ├── FacebookAds40.png ├── FacebookAds48.png ├── FacebookAds64.png ├── FacebookAds80.png ├── FacebookAds.query.pq ├── FacebookAds.mproj ├── FacebookAds.pq └── resources.resx ├── LICENSE ├── FacebookAds.sln └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | src/obj/ 2 | src/bin/ 3 | -------------------------------------------------------------------------------- /media/heading.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/media/heading.PNG -------------------------------------------------------------------------------- /media/output.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/media/output.PNG -------------------------------------------------------------------------------- /src/FacebookAds16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/src/FacebookAds16.png -------------------------------------------------------------------------------- /src/FacebookAds20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/src/FacebookAds20.png -------------------------------------------------------------------------------- /src/FacebookAds24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/src/FacebookAds24.png -------------------------------------------------------------------------------- /src/FacebookAds32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/src/FacebookAds32.png -------------------------------------------------------------------------------- /src/FacebookAds40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/src/FacebookAds40.png -------------------------------------------------------------------------------- /src/FacebookAds48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/src/FacebookAds48.png -------------------------------------------------------------------------------- /src/FacebookAds64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/src/FacebookAds64.png -------------------------------------------------------------------------------- /src/FacebookAds80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hugoberry/FacebookAds/HEAD/src/FacebookAds80.png -------------------------------------------------------------------------------- /src/FacebookAds.query.pq: -------------------------------------------------------------------------------- 1 | // Use this file to write queries to test your data connector 2 | let 3 | result = FacebookAds.API("/me/adaccounts",[fields="name"])[data]{0} 4 | in 5 | result -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /FacebookAds.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{4DF76451-A46A-4C0B-BE03-459FAAFA07E6}") = "FacebookAds", "src\FacebookAds.mproj", "{5B722117-0B4D-4C32-93DA-300DEB8C9F30}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | Release|x86 = Release|x86 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {5B722117-0B4D-4C32-93DA-300DEB8C9F30}.Debug|x86.ActiveCfg = Debug|x86 15 | {5B722117-0B4D-4C32-93DA-300DEB8C9F30}.Debug|x86.Build.0 = Debug|x86 16 | {5B722117-0B4D-4C32-93DA-300DEB8C9F30}.Release|x86.ActiveCfg = Release|x86 17 | {5B722117-0B4D-4C32-93DA-300DEB8C9F30}.Release|x86.Build.0 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {58508690-E0FD-4EBC-8615-69B592B9063E} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FacebooksAds PowerBI data connector 2 | PwerBI data connector for FacevookAds 3 | 4 | ![PowerBI](media/heading.PNG) 5 | 6 | ## Quickstart 7 | This module uses the extensibility provided by [Data Connectors](https://github.com/Microsoft/DataConnectors), so in order to use it you have to: 8 | 1. Create a `[My Documents]\Microsoft Power BI Desktop\Custom Connectors` directory 9 | 2. Enable the **Custom data connectors** preview feature in Power BI Desktop (under *File | Options and settings | Custom data connectors*) 10 | 3. Copy the the *.mez file from `/build` folder into the above folder 11 | 4. Restart Power BI Desktop 12 | 13 | 14 | ## For developers 15 | In order to extend the modules 16 | 1. Install the [Power Query SDK](https://aka.ms/powerquerysdk) from the Visual Studio Marketplace 17 | 2. Edit the existing `Data Connector Project` or *.pq files 18 | 3. Build the solution 19 | The deployable *.mez files will be located in the Debug folder of each module under `/src`. The Relese configuration of the build will copy these files into the `/build` folder. 20 | 21 | # Functions 22 | For additional examples and documentation please refer to the embeded documentation of each of the functions. 23 | ## FacebookAds.Campaign 24 | A function that returns statistical insights related to the campaigns associated with connected user 25 | 26 | `FacebookAds.Campaigns()` 27 | ### Output 28 | ![Output](media/output.PNG) 29 | 30 | ## FacebookAds.API 31 | Return a function which always returns a given value. 32 | 33 | `FacebookAds.API(URI as URI.Type, params as record)` 34 | 35 | Example 36 | `FacebookAds.API("/me/adaccounts",[fields="name"])[data]{0}` 37 | 38 | -------------------------------------------------------------------------------- /src/FacebookAds.mproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 6 | 7 | Exe 8 | MyRootNamespace 9 | MyAssemblyName 10 | False 11 | False 12 | True 13 | False 14 | True 15 | True 16 | True 17 | True 18 | False 19 | False 20 | 1000 21 | Yes 22 | FacebookAds 23 | 24 | 25 | false 26 | 27 | bin\Debug\ 28 | 29 | 30 | false 31 | ..\build\ 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Code 42 | 43 | 44 | Code 45 | 46 | 47 | Code 48 | 49 | 50 | Code 51 | 52 | 53 | Code 54 | 55 | 56 | Code 57 | 58 | 59 | Code 60 | 61 | 62 | Code 63 | 64 | 65 | Code 66 | 67 | 68 | Code 69 | 70 | 71 | Code 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /src/FacebookAds.pq: -------------------------------------------------------------------------------- 1 | // This file contains your Data Connector logic 2 | section FacebookAds; 3 | 4 | app_secret = Extension.LoadString("AppSecret"); 5 | app_id = Extension.LoadString("AppId"); 6 | redirectUrl = "https://preview.powerbi.com/views/oauthredirect.html"; 7 | windowWidth = 720; 8 | windowHeight = 1024; 9 | 10 | [DataSource.Kind="FacebookAds", Publish="FacebookAds.Publish"] 11 | shared FacebookAds.Campaigns = (optional url as text, optional params as record) => 12 | let 13 | key = Extension.CurrentCredential()[access_token], 14 | accountRequest = Web.Contents("https://graph.facebook.com/v2.11/me/adaccounts?"&Uri.BuildQueryString([access_token=key,fields="name"])), 15 | adaccounts = Json.Document(accountRequest)[data], 16 | out = UserToNavTabler(adaccounts) 17 | 18 | in 19 | out; 20 | 21 | [DataSource.Kind="FacebookAds"] 22 | shared FacebookAds.API = (optional url as text, optional params as record) => 23 | let 24 | key = Extension.CurrentCredential()[access_token], 25 | allParams = if params=null then [access_token=key] else [access_token=key]¶ms, 26 | apiRequest = Web.Contents("https://graph.facebook.com/v2.11"&url&"?"&Uri.BuildQueryString(allParams)), 27 | out = Json.Document(apiRequest) 28 | in 29 | out; 30 | 31 | UserToNavTabler = (users as list) => 32 | let 33 | navCol = {"Name","Key","Data","ItemKind", "ItemName", "IsLeaf"}, 34 | navRow = List.Accumulate(users,{},(s,c)=>s&{{c[name],c[id],GetAccountCampaignsInsights(c),"Table","Table",true}} ), 35 | objects = #table(navCol,navRow), 36 | out = Table.ToNavigationTable(objects, {"Key"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf") 37 | in 38 | out; 39 | 40 | GetAccountCampaignsInsights = (adaccount) => 41 | let 42 | key = Extension.CurrentCredential()[access_token], 43 | campaignsReq = Web.Contents("https://graph.facebook.com/v2.11/"&adaccount[id]&"/campaigns?"&Uri.BuildQueryString([access_token=key,fields="name"])), 44 | campaigns=Json.Document(campaignsReq)[data], 45 | out = List.Accumulate(campaigns,#table(null,{}),(s,c)=>s&GetCampaignInsights(c)) 46 | in 47 | out; 48 | 49 | GetCampaignInsights = (campaign) => 50 | let 51 | key = Extension.CurrentCredential()[access_token], 52 | insights = Web.Contents("https://graph.facebook.com/v2.11/"&campaign[id]&"/insights?"&Uri.BuildQueryString([access_token=key,fields="total_actions,reach,impressions,frequency,unique_clicks,spend"])), 53 | res = Json.Document(insights)[data], 54 | out = if res={} then campaign else campaign&res{0} 55 | in 56 | Table.FromRecords({out}); 57 | 58 | // Data Source Kind description 59 | FacebookAds = [ 60 | Authentication = [ 61 | 62 | OAuth = [ 63 | StartLogin = StartLogin, 64 | FinishLogin = FinishLogin, 65 | Label = Extension.LoadString("AuthenticationLabel") 66 | ] 67 | ], 68 | Label = Extension.LoadString("DataSourceLabel") 69 | ]; 70 | 71 | // Data Source UI publishing description 72 | FacebookAds.Publish = [ 73 | Beta = true, 74 | Category = "Other", 75 | ButtonText = { Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp") }, 76 | LearnMoreUrl = "https://powerbi.microsoft.com/", 77 | SourceImage = FacebookAds.Icons, 78 | SourceTypeImage = FacebookAds.Icons 79 | ]; 80 | 81 | FacebookAds.Icons = [ 82 | Icon16 = { Extension.Contents("FacebookAds16.png"), Extension.Contents("FacebookAds20.png"), Extension.Contents("FacebookAds24.png"), Extension.Contents("FacebookAds32.png") }, 83 | Icon32 = { Extension.Contents("FacebookAds32.png"), Extension.Contents("FacebookAds40.png"), Extension.Contents("FacebookAds48.png"), Extension.Contents("FacebookAds64.png") } 84 | ]; 85 | 86 | StartLogin = (resourceUrl, state, display) => 87 | let 88 | AuthorizeUrl = "https://www.facebook.com/v2.11/dialog/oauth?" & Uri.BuildQueryString([ 89 | client_id = app_id, 90 | redirect_uri = redirectUrl, 91 | scope="ads_read"]) 92 | in 93 | [ 94 | LoginUri = AuthorizeUrl, 95 | CallbackUri = redirectUrl, 96 | WindowHeight = windowHeight, 97 | WindowWidth = windowWidth, 98 | Context = null 99 | ]; 100 | 101 | FinishLogin = (context, callbackUri, state) => 102 | let 103 | parts = Uri.Parts(callbackUri)[Query], 104 | result = if (Record.HasFields(parts, {"error", "error_description"})) then 105 | error Error.Record(parts[error], parts[error_description], parts) 106 | else 107 | TokenMethod(parts[code]) 108 | in 109 | result; 110 | 111 | TokenMethod = (code) => 112 | let 113 | response = Web.Contents("https://graph.facebook.com/v2.11/oauth/access_token?" & Uri.BuildQueryString([ 114 | client_id = app_id, 115 | redirect_uri = redirectUrl, 116 | client_secret = app_secret, 117 | code = code]), 118 | [ManualStatusHandling = {400}]), 119 | body = Json.Document(response), 120 | result = if (Record.HasFields(body, {"error", "error_description"})) then 121 | error Error.Record(body[error], body[error_description], body) 122 | else 123 | body 124 | in 125 | result; 126 | 127 | Table.ToNavigationTable = ( 128 | table as table, 129 | keyColumns as list, 130 | nameColumn as text, 131 | dataColumn as text, 132 | itemKindColumn as text, 133 | itemNameColumn as text, 134 | isLeafColumn as text 135 | ) as table => 136 | let 137 | tableType = Value.Type(table), 138 | newTableType = Type.AddTableKey(tableType, keyColumns, true) meta 139 | [ 140 | NavigationTable.NameColumn = nameColumn, 141 | NavigationTable.DataColumn = dataColumn, 142 | NavigationTable.ItemKindColumn = itemKindColumn, 143 | Preview.DelayColumn = itemNameColumn, 144 | NavigationTable.IsLeafColumn = isLeafColumn 145 | ], 146 | navigationTable = Value.ReplaceType(table, newTableType) 147 | in 148 | navigationTable; -------------------------------------------------------------------------------- /src/resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 2041581656054412 122 | 123 | 124 | c20db9c91968cf6fa9b551252f4ee92d 125 | 126 | 127 | FacebookOAuth 128 | 129 | 130 | Connect to FacebookAds 131 | 132 | 133 | FacebookAds 134 | 135 | 136 | FacebookAds 137 | 138 | --------------------------------------------------------------------------------