Keyword Planner Code Example

This example demonstrates how to get keyword ideas and traffic estimates for search advertising campaigns.

Tip

Use the language selector in the documentation header to choose C#, Java, Php, or Python.

To get access and refresh tokens for your Microsoft Advertising user and make your first service call using the Bing Ads API, see the Quick Start guide. You'll want to review the Get Started guide and walkthroughs for your preferred language e.g., C#, Java, Php, and Python.

Supporting files for C#, Java, Php, and Python examples are available at GitHub. You can clone each repository or repurpose snippets as needed.

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;
using Microsoft.BingAds.V13.AdInsight;
using Microsoft.BingAds;

namespace BingAdsExamplesLibrary.V13
{
    /// <summary>
    /// How to get keyword ideas and traffic estimates for search advertising campaigns.
    /// </summary>
    public class KeywordPlanner : ExampleBase
    {
        public override string Description
        {
            get { return "Keyword Planner | AdInsight V13"; }
        }

        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                AdInsightExampleHelper AdInsightExampleHelper = new AdInsightExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);
                AdInsightExampleHelper.AdInsightService = new ServiceClient<IAdInsightService>(
                    authorizationData: authorizationData,
                    environment: environment);

                // Use the GetKeywordIdeaCategories operation to get a list of valid category identifiers.
                // A category identifier will be used in the CategorySearchParameter below.

                OutputStatusMessage("-----\nGetKeywordIdeaCategories:");
                var getKeywordIdeaCategoriesResponse = await AdInsightExampleHelper.GetKeywordIdeaCategoriesAsync();
                var categoryId = (long)(getKeywordIdeaCategoriesResponse?.KeywordIdeaCategories?.ToList()[0].CategoryId);
                OutputStatusMessage(string.Format("CategoryId {0} will be used in the CategorySearchParameter below", categoryId));

                // You must specify the attributes that you want in each returned KeywordIdea.

                var ideaAttributes = new List<KeywordIdeaAttribute>
                {
                    KeywordIdeaAttribute.AdGroupId,
                    KeywordIdeaAttribute.AdGroupName,
                    KeywordIdeaAttribute.AdImpressionShare,
                    KeywordIdeaAttribute.Competition,
                    KeywordIdeaAttribute.Keyword,
                    KeywordIdeaAttribute.MonthlySearchCounts,
                    KeywordIdeaAttribute.Relevance,
                    KeywordIdeaAttribute.Source,
                    KeywordIdeaAttribute.SuggestedBid,
                };

                var endDateTime = DateTime.UtcNow.AddMonths(-2);
                                
                // Only one of each SearchParameter type can be specified per call. 

                var searchParameters = new List<SearchParameter>
                {
                    // Determines the start and end month for MonthlySearchCounts data returned with each KeywordIdea.
                    // The date range search parameter is optional. If you do not include the DateRangeSearchParameter 
                    // in the GetKeywordIdeas request, then you will not be able to confirm whether the first list item 
                    // within MonthlySearchCounts is data for the previous month, or the month prior. If the date range is 
                    // specified and the most recent month's data is not yet available, then GetKeywordIdeas will return an error.

                    new DateRangeSearchParameter
                    {
                        EndDate = new DayMonthAndYear
                        {
                            Day = 30,
                            Month = 9,
                            Year = 2018
                        },
                        StartDate = new DayMonthAndYear
                        {
                            Day = 1,
                            Month = 9,
                            Year = 2018
                        },
                    },
                    
                    // The CategorySearchParameter corresponds to filling in 'Your product category' under
                    // 'Search for new keywords using a phrase, website, or category' in the 
                    // Microsoft Advertising web application's Keyword Planner tool.
                    // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.

                    new CategorySearchParameter
                    {
                        // Use the GetKeywordIdeaCategories operation to get a list of valid category identifiers.
                        CategoryId = categoryId
                    },

                    // The QuerySearchParameter corresponds to filling in 'Product or service' under
                    // 'Search for new keywords using a phrase, website, or category' in the 
                    // Microsoft Advertising web application's Keyword Planner tool.
                    // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.
                    // When calling GetKeywordIdeas, if ExpandIdeas = false the QuerySearchParameter is required. 

                    new QuerySearchParameter
                    {
                        Queries = new List<string>
                        {
                            "tennis",
                            "tennis shoes",
                            "running",
                            "running shoes",
                            "cross training",
                            "running",
                        },
                    },

                    // The UrlSearchParameter corresponds to filling in 'Your landing page' under
                    // 'Search for new keywords using a phrase, website, or category' in the 
                    // Microsoft Advertising web application's Keyword Planner tool.
                    // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.

                    new UrlSearchParameter
                    {
                        Url = "contoso.com"
                    },
                    
                    // The LanguageSearchParameter, LocationSearchParameter, and NetworkSearchParameter
                    // correspond to the 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category' ->
                    // 'Targeting' workflow in the Microsoft Advertising web application.
                    // Each of these search parameters are required.

                    new LanguageSearchParameter
                    {
                        // You must specify exactly one language

                        Languages = new List<LanguageCriterion>
                        {
                            new LanguageCriterion
                            {
                                Language = "English",
                            },
                        },
                    },
                    new LocationSearchParameter
                    {
                        // You must include at least one location.

                        Locations = new List<LocationCriterion>
                        {
                            new LocationCriterion
                            {
                                // United States
                                LocationId = 190,
                            },
                        }
                    },
                    new NetworkSearchParameter
                    {
                        Network = new NetworkCriterion
                        {
                            Network = NetworkType.OwnedAndOperatedAndSyndicatedSearch,
                        }
                    },

                    // The CompetitionSearchParameter, ExcludeAccountKeywordsSearchParameter, IdeaTextSearchParameter, 
                    // ImpressionShareSearchParameter, SearchVolumeSearchParameter, and SuggestedBidSearchParameter  
                    // correspond to the 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category' -> 
                    // 'Search options' workflow in the Microsoft Advertising web application.
                    // Use these options to refine what keywords we suggest. You can limit the keywords by historical data, 
                    // hide keywords already in your account, and include or exclude specific keywords.
                    // Each of these search parameters are optional.

                    new CompetitionSearchParameter
                    {
                        CompetitionLevels = new List<CompetitionLevel>
                        {
                            CompetitionLevel.High,
                            CompetitionLevel.Medium,
                            CompetitionLevel.Low
                        }
                    },
                    new ExcludeAccountKeywordsSearchParameter
                    {
                        ExcludeAccountKeywords = false,
                    },
                    new IdeaTextSearchParameter
                    {
                        // The match type is required. Only Broad is supported.

                        Excluded = new List<Keyword>
                        {
                            new Keyword
                            {
                                Text = "tennis court",
                                MatchType = MatchType.Broad
                            },
                            new Keyword
                            {
                                Text = "tennis pro",
                                MatchType = MatchType.Broad
                            }
                        },
                        Included = new List<Keyword>
                        {
                            new Keyword
                            {
                                Text = "athletic clothing",
                                MatchType = MatchType.Broad
                            },
                            new Keyword
                            {
                                Text = "athletic shoes",
                                MatchType = MatchType.Broad
                            }
                        },
                    },
                    new ImpressionShareSearchParameter
                    {
                        // Equivalent of '0 <= value <= 50'
                        Maximum = 50,
                        Minimum = 0,
                    },
                    new SearchVolumeSearchParameter
                    {
                        // Equivalent of 'value >= 50'
                        Maximum = null,
                        Minimum = 50,
                    },
                    new SuggestedBidSearchParameter
                    {
                        // Equivalent of both 'value <= 50' and '0 <= value <= 50'
                        Maximum = 50,
                        Minimum = null,
                    },

                    // Setting the device criterion is not available in the 
                    // 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category'
                    // workflow in the Microsoft Advertising web application.
                    // The DeviceSearchParameter is optional and by default the keyword ideas data
                    // are aggregated for all devices.

                    new DeviceSearchParameter
                    {
                        Device = new DeviceCriterion
                        {
                            // Possible values are All, Computers, Tablets, Smartphones
                            DeviceName = "All",
                        },
                    },
                };

                // If ExpandIdeas is false, the QuerySearchParameter is required.

                OutputStatusMessage("-----\nGetKeywordIdeas:");
                var getKeywordIdeasResponse = await AdInsightExampleHelper.GetKeywordIdeasAsync(
                    expandIdeas: true,
                    ideaAttributes: ideaAttributes,
                    searchParameters: searchParameters);

                var keywordIdeas = getKeywordIdeasResponse?.KeywordIdeas;
                if(keywordIdeas == null || keywordIdeas.Count < 1)
                {
                    OutputStatusMessage("No keyword ideas are available for the search parameters.");
                    return;
                }
                OutputStatusMessage("KeywordIdeas:");
                AdInsightExampleHelper.OutputArrayOfKeywordIdea(keywordIdeas);

                // Let's get traffic estimates for each returned keyword idea.

                // The returned ad group ID within each keyword idea will either be null or negative.
                // Negative identifiers can be used to map the keyword ideas into suggested new ad groups. 
                // A null ad group identifier indicates that the keyword idea was sourced from your 
                // keyword idea search parameter.

                // In this example we will use the suggested ad groups to request traffic estimates.
                // Each of the seed keyword ideas will be submitted in the same ad group.

                var adGroupIds = keywordIdeas.Select(idea => idea.AdGroupId).Distinct().ToList();
                var adGroupEstimatorCount = adGroupIds.Count;
                var seedOffset = adGroupIds.Contains(null) ? 0 : 1;
                
                var adGroupEstimators = new AdGroupEstimator[adGroupEstimatorCount];
                for(int index = 0; index < adGroupEstimatorCount; index++)
                {
                    adGroupEstimators[index] = new AdGroupEstimator
                    {
                        // The AdGroupId is reserved for future use.
                        // The traffic estimates are not based on any specific ad group. 
                        AdGroupId = null,

                        // We will add new keyword estimators while iterating the keyword ideas below.
                        KeywordEstimators = new List<KeywordEstimator>(),

                        // Optionally you can set an ad group level max CPC (maximum search bid)
                        MaxCpc = 5.00
                    };
                }

                foreach(var keywordIdea in keywordIdeas)
                {
                    var keywordEstimator = new KeywordEstimator
                    {
                        Keyword = new Keyword
                        {
                            // The keyword Id is reserved for future use.
                            // The returned estimates are not based on any specific keyword.
                            Id = null,
                            
                            // The match type is required. Exact, Broad, and Phrase are supported.
                            MatchType = MatchType.Exact,

                            // Use the suggested keyword
                            Text = keywordIdea.Keyword
                        },

                        // Round the suggested bid to two decimal places
                        MaxCpc = keywordIdea.SuggestedBid > 0.04 ? keywordIdea.SuggestedBid : null,
                    };

                    var index = keywordIdea.AdGroupId != null ? -(long)keywordIdea.AdGroupId - seedOffset : 0;

                    adGroupEstimators[index].KeywordEstimators.Add(keywordEstimator);
                }

                // Currently you can include only one CampaignEstimator per service call.

                var campaigns = new List<CampaignEstimator>
                {
                    new CampaignEstimator
                    {
                        // Let's use the ad group and keyword estimators that were sourced from keyword ideas above.

                        AdGroupEstimators = adGroupEstimators,

                        // The CampaignId is reserved for future use.
                        // The returned estimates are not based on any specific campaign.

                        CampaignId = null,

                        DailyBudget = 50.00,

                        NegativeKeywords = new List<NegativeKeyword>
                        {
                            new NegativeKeyword
                            {
                                Text = "foo",
                                MatchType = MatchType.Exact,
                            },
                        },

                        // The location, language, and network criterions are required for traffic estimates.

                        Criteria = new List<Criterion>
                        {
                            // You must include at least one location.

                            new LocationCriterion
                            {
                                // United States
                                LocationId = 190
                            },

                            // You must specify exactly one language criterion

                            new LanguageCriterion
                            {
                                Language = "English"
                            },

                            // You must specify exactly one network criterion

                            new NetworkCriterion
                            {
                                Network = NetworkType.OwnedAndOperatedAndSyndicatedSearch
                            },

                            // Optionally you can specify exactly one device.
                            // If you do not specify a device, the returned traffic estimates 
                            // are aggregated for all devices.
                            // The "All" device name is equivalent to omitting the DeviceCriterion.

                            new DeviceCriterion
                            {
                                DeviceName = "All"
                            },
                        },
                    },
                };

                OutputStatusMessage("-----\nGetKeywordTrafficEstimates:");
                var getKeywordTrafficEstimatesResponse = await AdInsightExampleHelper.GetKeywordTrafficEstimatesAsync(
                    campaignEstimators: campaigns);
                OutputStatusMessage("CampaignEstimates:");
                AdInsightExampleHelper.OutputArrayOfCampaignEstimate(getKeywordTrafficEstimatesResponse?.CampaignEstimates);
            }
            // Catch authentication exceptions
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch AdInsight service exceptions
            catch (FaultException<AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }
    }
}
package com.microsoft.bingads.examples.v13;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;

import com.microsoft.bingads.*;
import com.microsoft.bingads.v13.adinsight.*;

public class KeywordPlanner extends ExampleBase {
    
    public static void main(java.lang.String[] args) {
     
        try
        {
            authorizationData = getAuthorizationData(); 
             
            AdInsightExampleHelper.AdInsightService = new ServiceClient<IAdInsightService>(
                    authorizationData, 
                    API_ENVIRONMENT,
                    IAdInsightService.class);
                         
            // Use the GetKeywordIdeaCategories operation to get a list of valid category identifiers.
            // A category identifier will be used in the CategorySearchParameter below.
            
            outputStatusMessage("-----\nGetKeywordIdeaCategories:");
            GetKeywordIdeaCategoriesResponse getKeywordIdeaCategoriesResponse = AdInsightExampleHelper.getKeywordIdeaCategories();
            if(getKeywordIdeaCategoriesResponse == null){
                outputStatusMessage(String.format("This example requires keyword categories."));
                return;
            }
            java.lang.Long categoryId = (long)(getKeywordIdeaCategoriesResponse.getKeywordIdeaCategories().getKeywordIdeaCategories().get(0).getCategoryId());
            outputStatusMessage(String.format("CategoryId %s will be used in the CategorySearchParameter below", categoryId));

            // You must specify the attributes that you want in each returned KeywordIdea.

            ArrayOfKeywordIdeaAttribute ideaAttributes = new ArrayOfKeywordIdeaAttribute();
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.AD_GROUP_ID);
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.AD_GROUP_NAME);
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.AD_IMPRESSION_SHARE);
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.COMPETITION);
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.KEYWORD);
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.MONTHLY_SEARCH_COUNTS);
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.RELEVANCE);
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.SOURCE);
            ideaAttributes.getKeywordIdeaAttributes().add(KeywordIdeaAttribute.SUGGESTED_BID);
                        
            // Only one of each SearchParameter type can be specified per call. 

            ArrayOfSearchParameter searchParameters = new ArrayOfSearchParameter();
            
            // Determines the start and end month for MonthlySearchCounts data returned with each KeywordIdea.
            // The date range search parameter is optional. If you do not include the DateRangeSearchParameter 
            // in the GetKeywordIdeas request, then you will not be able to confirm whether the first list item 
            // within MonthlySearchCounts is data for the previous month, or the month prior. If the date range is 
            // specified and the most recent month's data is not yet available, then GetKeywordIdeas will return an error.

            Calendar calendar = Calendar.getInstance();
            DateRangeSearchParameter dateRangeSearchParameter = new DateRangeSearchParameter();
            DayMonthAndYear endDate = new DayMonthAndYear();
            endDate.setDay(30);
            endDate.setMonth(9);
            endDate.setYear(2018);
            DayMonthAndYear startDate = new DayMonthAndYear();
            startDate.setDay(1);
            startDate.setMonth(9);
            startDate.setYear(2018);
            dateRangeSearchParameter.setEndDate(endDate);
            dateRangeSearchParameter.setStartDate(startDate);            
            searchParameters.getSearchParameters().add(dateRangeSearchParameter);

            // The CategorySearchParameter corresponds to filling in 'Your product category' under
            // 'Search for new keywords using a phrase, website, or category' in the 
            // Bing Ads web application's Keyword Planner tool.
            // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.

            CategorySearchParameter categorySearchParameter = new CategorySearchParameter();
            // Use the GetKeywordIdeaCategories operation (e.g., above) to get a list of valid category identifiers.
            categorySearchParameter.setCategoryId(categoryId);            
            searchParameters.getSearchParameters().add(categorySearchParameter);

            // The QuerySearchParameter corresponds to filling in 'Product or service' under
            // 'Search for new keywords using a phrase, website, or category' in the 
            // Bing Ads web application's Keyword Planner tool.
            // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.
            // When calling GetKeywordIdeas, if ExpandIdeas = false the QuerySearchParameter is required. 

            QuerySearchParameter querySearchParameter = new QuerySearchParameter();
            ArrayOfstring queries = new ArrayOfstring();
            queries.getStrings().add("tennis");
            queries.getStrings().add("tennis shoes");
            queries.getStrings().add("running");
            queries.getStrings().add("running shoes");
            queries.getStrings().add("cross training");          
            querySearchParameter.setQueries(queries);            
            searchParameters.getSearchParameters().add(querySearchParameter);
            
            // The UrlSearchParameter corresponds to filling in 'Your landing page' under
            // 'Search for new keywords using a phrase, website, or category' in the 
            // Bing Ads web application's Keyword Planner tool.
            // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.

            UrlSearchParameter urlSearchParameter = new UrlSearchParameter();
            urlSearchParameter.setUrl("contoso.com");            
            searchParameters.getSearchParameters().add(urlSearchParameter);
            
            // The LanguageSearchParameter, LocationSearchParameter, and NetworkSearchParameter
            // correspond to the 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category' ->
            // 'Targeting' workflow in the Bing Ads web application.
            // Each of these search parameters are required.

            LanguageSearchParameter languageSearchParameter = new LanguageSearchParameter();
            ArrayOfLanguageCriterion languages = new ArrayOfLanguageCriterion();
            LanguageCriterion englishLanguage =  new LanguageCriterion();
            englishLanguage.setLanguage("English");  
            // You must specify exactly one language
            languages.getLanguageCriterions().add(englishLanguage);
            languageSearchParameter.setLanguages(languages);               
            searchParameters.getSearchParameters().add(languageSearchParameter);
                    
            LocationSearchParameter locationSearchParameter = new LocationSearchParameter();
            ArrayOfLocationCriterion locations = new ArrayOfLocationCriterion();
            LocationCriterion unitedStatesLocationCriterion = new LocationCriterion();
            // United States
            unitedStatesLocationCriterion.setLocationId(190L);
            // You must specify between 1 and 100 locations
            locations.getLocationCriterions().add(unitedStatesLocationCriterion);
            locationSearchParameter.setLocations(locations);                   
            searchParameters.getSearchParameters().add(locationSearchParameter);
                    
            NetworkSearchParameter networkSearchParameter = new NetworkSearchParameter();
            NetworkCriterion networkCriterion = new NetworkCriterion();
            networkCriterion.setNetwork(NetworkType.OWNED_AND_OPERATED_AND_SYNDICATED_SEARCH);
            networkSearchParameter.setNetwork(networkCriterion);            
            searchParameters.getSearchParameters().add(networkSearchParameter);
            
            // The CompetitionSearchParameter, ExcludeAccountKeywordsSearchParameter, IdeaTextSearchParameter, 
            // ImpressionShareSearchParameter, SearchVolumeSearchParameter, and SuggestedBidSearchParameter  
            // correspond to the 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category' -> 
            // 'Search options' workflow in the Bing Ads web application.
            // Use these options to refine what keywords we suggest. You can limit the keywords by historical data, 
            // hide keywords already in your account, and include or exclude specific keywords.
            // Each of these search parameters are optional.

            CompetitionSearchParameter competitionSearchParameter = new CompetitionSearchParameter();
            ArrayOfCompetitionLevel competitionLevels = new ArrayOfCompetitionLevel();
            competitionLevels.getCompetitionLevels().add(CompetitionLevel.LOW);
            competitionLevels.getCompetitionLevels().add(CompetitionLevel.MEDIUM);
            competitionLevels.getCompetitionLevels().add(CompetitionLevel.HIGH);
            competitionSearchParameter.setCompetitionLevels(competitionLevels);            
            searchParameters.getSearchParameters().add(competitionSearchParameter);
            
            ExcludeAccountKeywordsSearchParameter excludeAccountKeywordsSearchParameter = new ExcludeAccountKeywordsSearchParameter();
            excludeAccountKeywordsSearchParameter.setExcludeAccountKeywords(false);
            searchParameters.getSearchParameters().add(excludeAccountKeywordsSearchParameter);
            
            
            IdeaTextSearchParameter ideaTextSearchParameter = new IdeaTextSearchParameter();
            // The match type is required. Only Broad is supported.
            ArrayOfKeyword excludedKeywords = new ArrayOfKeyword();
            Keyword excludedKeyword1 = new Keyword();
            excludedKeyword1.setText("tennis court");
            excludedKeyword1.setMatchType(MatchType.BROAD);
            excludedKeywords.getKeywords().add(excludedKeyword1);
            Keyword excludedKeyword2 = new Keyword();
            excludedKeyword2.setText("tennis pro");
            excludedKeyword2.setMatchType(MatchType.BROAD);
            excludedKeywords.getKeywords().add(excludedKeyword2);
            ArrayOfKeyword includedKeywords = new ArrayOfKeyword();
            Keyword includedKeyword1 = new Keyword();
            includedKeyword1.setText("athletic clothing");
            includedKeyword1.setMatchType(MatchType.BROAD);
            includedKeywords.getKeywords().add(includedKeyword1);
            Keyword includedKeyword2 = new Keyword();
            includedKeyword2.setText("athletic shoes");
            includedKeyword2.setMatchType(MatchType.BROAD);
            includedKeywords.getKeywords().add(includedKeyword2);
            ideaTextSearchParameter.setExcluded(excludedKeywords);
            ideaTextSearchParameter.setIncluded(includedKeywords);
            searchParameters.getSearchParameters().add(ideaTextSearchParameter);
            
            // Equivalent of '0 <= value <= 50'
            ImpressionShareSearchParameter impressionShareSearchParameter = new ImpressionShareSearchParameter();
            impressionShareSearchParameter.setMaximum(50D);
            impressionShareSearchParameter.setMinimum(0D);
            searchParameters.getSearchParameters().add(impressionShareSearchParameter);
            
            // Equivalent of 'value >= 50'
            SearchVolumeSearchParameter searchVolumeSearchParameter = new SearchVolumeSearchParameter();
            searchVolumeSearchParameter.setMaximum(null);
            searchVolumeSearchParameter.setMinimum(50L);
            searchParameters.getSearchParameters().add(searchVolumeSearchParameter);
                        
            // Equivalent of both 'value <= 50' and '0 <= value <= 50'
            SuggestedBidSearchParameter suggestedBidSearchParameter = new SuggestedBidSearchParameter();
            suggestedBidSearchParameter.setMaximum(50D);
            suggestedBidSearchParameter.setMinimum(null);
            searchParameters.getSearchParameters().add(suggestedBidSearchParameter);

            // Setting the device criterion is not available in the 
            // 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category'
            // workflow in the Bing Ads web application.
            // The DeviceSearchParameter is optional and by default the keyword ideas data
            // are aggregated for all devices.
            
            DeviceSearchParameter deviceSearchParameter = new DeviceSearchParameter();
            DeviceCriterion deviceCriterion = new DeviceCriterion();
            // Possible values are All, Computers, Tablets, Smartphones
            deviceCriterion.setDeviceName("All");
            deviceSearchParameter.setDevice(deviceCriterion);
            searchParameters.getSearchParameters().add(deviceSearchParameter);

            // If ExpandIdeas is false, the QuerySearchParameter is required.

            outputStatusMessage("-----\nGetKeywordIdeas:");
            GetKeywordIdeasResponse getKeywordIdeasResponse = AdInsightExampleHelper.getKeywordIdeas(
                true,
                ideaAttributes,
                searchParameters);

            ArrayOfKeywordIdea keywordIdeas = getKeywordIdeasResponse.getKeywordIdeas();
            if(keywordIdeas == null || keywordIdeas.getKeywordIdeas().size() < 1)
            {
                outputStatusMessage("No keyword ideas are available for the search parameters.");
                return;
            }
            outputStatusMessage("KeywordIdeas:");
            AdInsightExampleHelper.outputArrayOfKeywordIdea(keywordIdeas);

            // Let's get traffic estimates for each returned keyword idea.

            // The returned ad group ID within each keyword idea will either be null or negative.
            // Negative identifiers can be used to map the keyword ideas into suggested new ad groups. 
            // A null ad group identifier indicates that the keyword idea was sourced from your 
            // keyword idea search parameter.

            // In this example we will use the suggested ad groups to request traffic estimates.
            // Each of the seed keyword ideas will be submitted in the same ad group.

            ArrayOflong keywordIdeaAdGroupIds = new ArrayOflong();
            for(KeywordIdea keywordIdea : keywordIdeas.getKeywordIdeas()){
                keywordIdeaAdGroupIds.getLongs().add(keywordIdea.getAdGroupId());
            }
            ArrayList<java.lang.Long> adGroupIds = new ArrayList<java.lang.Long>(new HashSet<Long>(keywordIdeaAdGroupIds.getLongs()));
            
            int adGroupEstimatorCount = adGroupIds.size();
            int seedOffset = adGroupIds.contains(null) ? 0 : 1;

            AdGroupEstimator[] adGroupEstimators = new AdGroupEstimator[adGroupEstimatorCount];
            for(int index = 0; index < adGroupEstimatorCount; index++)
            {
                adGroupEstimators[index] = new AdGroupEstimator();
                
                // The AdGroupId is reserved for future use.
                // The traffic estimates are not based on any specific ad group. 
                adGroupEstimators[index].setAdGroupId(null);
                
                // Optionally you can set an ad group level max CPC (maximum search bid)
                adGroupEstimators[index].setMaxCpc(5.00D);
                
                // We will add new keyword estimators while iterating the keyword ideas below.
                ArrayOfKeywordEstimator keywordEstimators = new ArrayOfKeywordEstimator();
                adGroupEstimators[index].setKeywordEstimators(keywordEstimators);
            }

            for(KeywordIdea keywordIdea : keywordIdeas.getKeywordIdeas())
            {
                KeywordEstimator keywordEstimator = new KeywordEstimator();
                Keyword keyword = new Keyword();
                // The keyword Id is reserved for future use.
                // The returned estimates are not based on any specific keyword.
                keyword.setId(null);
                // The match type is required. Exact, Broad, and Phrase are supported.
                keyword.setMatchType(MatchType.EXACT);
                // Use the suggested keyword
                keyword.setText(keywordIdea.getKeyword());
                keywordEstimator.setKeyword(keyword);
                double maxCpc = keywordIdea.getSuggestedBid() > 0.04 ? 
                        keywordIdea.getSuggestedBid() : null;
                keywordEstimator.setMaxCpc(maxCpc);
                
                long index = keywordIdea.getAdGroupId() != null ? -(long)keywordIdea.getAdGroupId() - seedOffset : 0;

                adGroupEstimators[(int)index].getKeywordEstimators().getKeywordEstimators().add(keywordEstimator);
            }

            // Currently you can include only one CampaignEstimator per service call.

            ArrayOfCampaignEstimator campaigns = new ArrayOfCampaignEstimator();
            CampaignEstimator campaignEstimator = new CampaignEstimator();
                        
            // Let's use the ad group and keyword estimators that were sourced from keyword ideas above.
            ArrayOfAdGroupEstimator adGroups = new ArrayOfAdGroupEstimator();
            for(int index = 0; index < adGroupEstimatorCount; index++)
            {
                adGroups.getAdGroupEstimators().add(adGroupEstimators[index]);
            }
            campaignEstimator.setAdGroupEstimators(adGroups);
           
            // The CampaignId is reserved for future use.
            // The returned estimates are not based on any specific campaign.
            campaignEstimator.setCampaignId(null);

            campaignEstimator.setDailyBudget(50.00D);

            ArrayOfNegativeKeyword negativeKeywords = new ArrayOfNegativeKeyword();
            NegativeKeyword negativeKeyword = new NegativeKeyword();
            negativeKeyword.setText("foo");
            negativeKeyword.setMatchType(MatchType.EXACT);
            negativeKeywords.getNegativeKeywords().add(negativeKeyword);            
            campaignEstimator.setNegativeKeywords(negativeKeywords);

            // The location, language, and network criterions are required for traffic estimates.

            ArrayOfCriterion trafficEstimateCriteria = new ArrayOfCriterion();
            // You must specify between 1 and 100 locations
            trafficEstimateCriteria.getCriterions().add(unitedStatesLocationCriterion);
            // You must specify exactly one language criterion
            trafficEstimateCriteria.getCriterions().add(englishLanguage);
            // You must specify exactly one network criterion
            trafficEstimateCriteria.getCriterions().add(networkCriterion);
            // Optionally you can specify exactly one device.
            // If you do not specify a device, the returned traffic estimates 
            // are aggregated for all devices.
            // The "All" device name is equivalent to omitting the DeviceCriterion.
            trafficEstimateCriteria.getCriterions().add(deviceCriterion);
            campaignEstimator.setCriteria(trafficEstimateCriteria);
            
            campaigns.getCampaignEstimators().add(campaignEstimator);
            
            outputStatusMessage("-----\nGetKeywordTrafficEstimates:");
            GetKeywordTrafficEstimatesResponse getKeywordTrafficEstimatesResponse = AdInsightExampleHelper.getKeywordTrafficEstimates(
                    campaigns);
            outputStatusMessage("CampaignEstimates:");
            AdInsightExampleHelper.outputArrayOfCampaignEstimate(getKeywordTrafficEstimatesResponse.getCampaignEstimates());        
        } 
        catch (Exception ex) {
            String faultXml = ExampleExceptionHelper.getBingAdsExceptionFaultXml(ex, System.out);
            outputStatusMessage(faultXml);
            String message = ExampleExceptionHelper.handleBingAdsSDKException(ex, System.out);
            outputStatusMessage(message);
        }
    }
}
<?php

namespace Microsoft\BingAds\Samples\V13;

// For more information about installing and using the Bing Ads PHP SDK, 
// see https://go.microsoft.com/fwlink/?linkid=838593.

require_once __DIR__ . "/../vendor/autoload.php";

include __DIR__ . "/AuthHelper.php";
include __DIR__ . "/AdInsightExampleHelper.php";
include __DIR__ . "/CampaignManagementExampleHelper.php";

use SoapVar;
use SoapFault;
use Exception;
use DateTime;

// Specify the Microsoft\BingAds\Auth classes that will be used.
use Microsoft\BingAds\Auth\ServiceClient;
use Microsoft\BingAds\Auth\ServiceClientType;

// Specify the Microsoft\BingAds\Samples classes that will be used.
use Microsoft\BingAds\Samples\V13\AuthHelper;
use Microsoft\BingAds\Samples\V13\AdInsightExampleHelper;

// Specify the Microsoft\BingAds\V13\AdInsight classes that will be used.
use Microsoft\BingAds\V13\AdInsight\KeywordIdeaAttribute;
use Microsoft\BingAds\V13\AdInsight\SearchParameter;
use Microsoft\BingAds\V13\AdInsight\DateRangeSearchParameter;
use Microsoft\BingAds\V13\AdInsight\DayMonthAndYear;
use Microsoft\BingAds\V13\AdInsight\CategorySearchParameter;
use Microsoft\BingAds\V13\AdInsight\QuerySearchParameter;
use Microsoft\BingAds\V13\AdInsight\UrlSearchParameter;
use Microsoft\BingAds\V13\AdInsight\LanguageSearchParameter;
use Microsoft\BingAds\V13\AdInsight\Criterion;
use Microsoft\BingAds\V13\AdInsight\LanguageCriterion;
use Microsoft\BingAds\V13\AdInsight\LocationSearchParameter;
use Microsoft\BingAds\V13\AdInsight\LocationCriterion;
use Microsoft\BingAds\V13\AdInsight\NetworkSearchParameter;
use Microsoft\BingAds\V13\AdInsight\NetworkCriterion;
use Microsoft\BingAds\V13\AdInsight\NetworkType;
use Microsoft\BingAds\V13\AdInsight\CompetitionSearchParameter;
use Microsoft\BingAds\V13\AdInsight\CompetitionLevel;
use Microsoft\BingAds\V13\AdInsight\ExcludeAccountKeywordsSearchParameter;
use Microsoft\BingAds\V13\AdInsight\IdeaTextSearchParameter;
use Microsoft\BingAds\V13\AdInsight\Keyword;
use Microsoft\BingAds\V13\AdInsight\MatchType;
use Microsoft\BingAds\V13\AdInsight\ImpressionShareSearchParameter;
use Microsoft\BingAds\V13\AdInsight\SearchVolumeSearchParameter;
use Microsoft\BingAds\V13\AdInsight\SuggestedBidSearchParameter;
use Microsoft\BingAds\V13\AdInsight\DeviceSearchParameter;
use Microsoft\BingAds\V13\AdInsight\DeviceCriterion;
use Microsoft\BingAds\V13\AdInsight\AdGroupEstimator;
use Microsoft\BingAds\V13\AdInsight\KeywordEstimator;
use Microsoft\BingAds\V13\AdInsight\CampaignEstimator;
use Microsoft\BingAds\V13\AdInsight\AdGroupEstimate;
use Microsoft\BingAds\V13\AdInsight\KeywordEstimate;
use Microsoft\BingAds\V13\AdInsight\CampaignEstimate;
use Microsoft\BingAds\V13\AdInsight\NegativeKeyword;

try
{
    // Authenticate user credentials and set the account ID for the sample.  
    AuthHelper::Authenticate();

    print("-----\r\nGetKeywordIdeaCategories:\r\n");
    $getKeywordIdeaCategoriesResponse = AdInsightExampleHelper::GetKeywordIdeaCategories();
    $categoryId = $getKeywordIdeaCategoriesResponse->KeywordIdeaCategories->KeywordIdeaCategory[0]->CategoryId;
    printf("CategoryId %s will be used in the CategorySearchParameter below\r\n", $categoryId);
    
    // You must specify the attributes that you want in each returned KeywordIdea.

    $ideaAttributes = array();
    $ideaAttributes[] = KeywordIdeaAttribute::AdGroupId;
    $ideaAttributes[] = KeywordIdeaAttribute::AdGroupName;
    $ideaAttributes[] = KeywordIdeaAttribute::AdImpressionShare;
    $ideaAttributes[] = KeywordIdeaAttribute::Competition;
    $ideaAttributes[] = KeywordIdeaAttribute::Keyword;
    $ideaAttributes[] = KeywordIdeaAttribute::MonthlySearchCounts;
    $ideaAttributes[] = KeywordIdeaAttribute::Relevance;
    $ideaAttributes[] = KeywordIdeaAttribute::Source;
    $ideaAttributes[] = KeywordIdeaAttribute::SuggestedBid;

    date_default_timezone_set('UTC');
    $now = new DateTime(gmdate('Y-m-d H:i:s', time()));

    // Only one of each SearchParameter type can be specified per call. 

    $searchParameters = array();

    // Determines the start and end month for MonthlySearchCounts data returned with each KeywordIdea.
    // The date range search parameter is optional. If you do not include the DateRangeSearchParameter 
    // in the GetKeywordIdeas request, then you will not be able to confirm whether the first list item 
    // within MonthlySearchCounts is data for the previous month, or the month prior. If the date range is 
    // specified and the most recent month's data is not yet available, then GetKeywordIdeas will return an error.

    $dateRangeSearchParameter = new DateRangeSearchParameter();
    $dateRangeSearchParameterEndDate = new DayMonthAndYear();
    $dateRangeSearchParameterEndDate->Day = 30;
    $dateRangeSearchParameterEndDate->Month = 9;
    $dateRangeSearchParameterEndDate->Year = 2018;
    $dateRangeSearchParameter->EndDate = $dateRangeSearchParameterEndDate;
    $dateRangeSearchParameterStartDate = new DayMonthAndYear();
    $dateRangeSearchParameterStartDate->Day = 1;
    $dateRangeSearchParameterStartDate->Month = 9;
    $dateRangeSearchParameterStartDate->Year = 2018;
    $dateRangeSearchParameter->StartDate = $dateRangeSearchParameterStartDate;
    $searchParameters[] = new SoapVar(
        $dateRangeSearchParameter, 
        SOAP_ENC_OBJECT, 
        'DateRangeSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );
    
    // The CategorySearchParameter corresponds to filling in 'Your product category' under
    // 'Search for new keywords using a phrase, website, or category' in the 
    // Bing Ads web application's Keyword Planner tool.
    // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.
    
    $categorySearchParameter = new CategorySearchParameter();
    $categorySearchParameter->CategoryId = $categoryId;
    $searchParameters[] = new SoapVar(
        $categorySearchParameter, 
        SOAP_ENC_OBJECT, 
        'CategorySearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    // The QuerySearchParameter corresponds to filling in 'Product or service' under
    // 'Search for new keywords using a phrase, website, or category' in the 
    // Bing Ads web application's Keyword Planner tool.
    // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.
    // When calling GetKeywordIdeas, if ExpandIdeas = false the QuerySearchParameter is required. 

    $querySearchParameter = new QuerySearchParameter();
    $querySearchParameter->Queries = array("tennis", "tennis shoes", "running", "running shoes", "cross training", "running");
    $searchParameters[] = new SoapVar(
        $querySearchParameter, 
        SOAP_ENC_OBJECT, 
        'QuerySearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    // The UrlSearchParameter corresponds to filling in 'Your landing page' under
    // 'Search for new keywords using a phrase, website, or category' in the 
    // Bing Ads web application's Keyword Planner tool.
    // One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.

    $urlSearchParameter = new UrlSearchParameter();
    $urlSearchParameter->Url = "contoso.com";
    $searchParameters[] = new SoapVar(
        $urlSearchParameter, 
        SOAP_ENC_OBJECT, 
        'UrlSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );
    
    // The LanguageSearchParameter, LocationSearchParameter, and NetworkSearchParameter
    // correspond to the 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category' ->
    // 'Targeting' workflow in the Bing Ads web application.
    // Each of these search parameters are required.

    $languageSearchParameter = new LanguageSearchParameter();
    $languageCriterion = new LanguageCriterion();
    $languageCriterion->Language = "English";
    // You must specify exactly one language
    $languageSearchParameter->Languages[] = new SoapVar(
        $languageCriterion, 
        SOAP_ENC_OBJECT, 
        'LanguageCriterion', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );
    $searchParameters[] = new SoapVar(
        $languageSearchParameter, 
        SOAP_ENC_OBJECT, 
        'LanguageSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    $locationSearchParameter = new LocationSearchParameter();
    $locationSearchParameter->Locations = array();
    $locationCriterion = new LocationCriterion();
    // United States
    $locationCriterion->LocationId = 190;
    // You must specify between 1 and 100 locations
    $locationSearchParameter->Locations[] = new SoapVar(
        $locationCriterion, 
        SOAP_ENC_OBJECT, 
        'LocationCriterion', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );
    $searchParameters[] = new SoapVar(
        $locationSearchParameter, 
        SOAP_ENC_OBJECT, 
        'LocationSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    $networkSearchParameter = new NetworkSearchParameter();
    $networkCriterion = new NetworkCriterion();
    $networkCriterion->Network = NetworkType::OwnedAndOperatedAndSyndicatedSearch;
    $networkSearchParameter->Network = new SoapVar(
        $networkCriterion, 
        SOAP_ENC_OBJECT, 
        'NetworkCriterion', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );
    $searchParameters[] = new SoapVar(
        $networkSearchParameter, 
        SOAP_ENC_OBJECT, 
        'NetworkSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    // The CompetitionSearchParameter, ExcludeAccountKeywordsSearchParameter, IdeaTextSearchParameter, 
    // ImpressionShareSearchParameter, SearchVolumeSearchParameter, and SuggestedBidSearchParameter  
    // correspond to the 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category' -> 
    // 'Search options' workflow in the Bing Ads web application.
    // Use these options to refine what keywords we suggest. You can limit the keywords by historical data, 
    // hide keywords already in your account, and include or exclude specific keywords.
    // Each of these search parameters are optional.

    $competitionSearchParameter = new CompetitionSearchParameter();
    $competitionLevels = array(CompetitionLevel::High, CompetitionLevel::Medium, CompetitionLevel::Low);
    $competitionSearchParameter->CompetitionLevels = $competitionLevels;
    $searchParameters[] = new SoapVar(
        $competitionSearchParameter, 
        SOAP_ENC_OBJECT, 
        'CompetitionSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    $excludeAccountKeywordsSearchParameter = new ExcludeAccountKeywordsSearchParameter();
    $excludeAccountKeywordsSearchParameter->ExcludeAccountKeywords = false;
    $searchParameters[] = new SoapVar(
        $excludeAccountKeywordsSearchParameter, 
        SOAP_ENC_OBJECT, 
        'ExcludeAccountKeywordsSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    $ideaTextSearchParameter = new IdeaTextSearchParameter();
    $excludedKeywords = array();
    $excludedKeyword1 = new Keyword();
    $excludedKeyword1->Text = "tennis court";
    // The match type is required. Only Broad is supported.
    $excludedKeyword1->MatchType = MatchType::Broad;
    $excludedKeywords[] = $excludedKeyword1;
    $excludedKeyword2 = new Keyword();
    $excludedKeyword2->Text = "tennis pro";
    $excludedKeyword2->MatchType = MatchType::Broad;
    $excludedKeywords[] = $excludedKeyword2;
    $ideaTextSearchParameter->Excluded = $excludedKeywords;
    $includedKeyword1 = new Keyword();
    $includedKeyword1->Text = "athletic clothing";
    $includedKeyword1->MatchType = MatchType::Broad;
    $includedKeywords[] = $includedKeyword1;
    $includedKeyword2 = new Keyword();
    $includedKeyword2->Text = "athletic shoes";
    $includedKeyword2->MatchType = MatchType::Broad;
    $includedKeywords[] = $includedKeyword2;
    $ideaTextSearchParameter->Included = $includedKeywords;
    $searchParameters[] = new SoapVar(
        $ideaTextSearchParameter, 
        SOAP_ENC_OBJECT, 
        'IdeaTextSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    $impressionShareSearchParameter = new ImpressionShareSearchParameter();
    // Equivalent of '0 <= value <= 50'
    $impressionShareSearchParameter->Maximum = 50;
    $impressionShareSearchParameter->Minimum = 0;
    $searchParameters[] = new SoapVar(
        $impressionShareSearchParameter, 
        SOAP_ENC_OBJECT, 
        'ImpressionShareSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    $searchVolumeSearchParameter = new SearchVolumeSearchParameter();
    // Equivalent of 'value >= 50'
    $searchVolumeSearchParameter->Maximum = null;
    $searchVolumeSearchParameter->Minimum = 50;
    $searchParameters[] = new SoapVar(
        $searchVolumeSearchParameter, 
        SOAP_ENC_OBJECT, 
        'SearchVolumeSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    $suggestedBidSearchParameter = new SuggestedBidSearchParameter();
    // Equivalent of both 'value <= 50' and '0 <= value <= 50'
    $suggestedBidSearchParameter->Maximum = 50;
    $suggestedBidSearchParameter->Minimum = null;
    $searchParameters[] = new SoapVar(
        $suggestedBidSearchParameter,
         SOAP_ENC_OBJECT, 
         'SuggestedBidSearchParameter', 
         $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    // Setting the device criterion is not available in the 
    // 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category'
    // workflow in the Bing Ads web application.
    // The DeviceSearchParameter is optional and by default the keyword ideas data
    // are aggregated for all devices.

    $deviceSearchParameter = new DeviceSearchParameter();
    $deviceCriterion = new DeviceCriterion();
    // Possible values are All, Computers, Tablets, Smartphones
    $deviceCriterion->DeviceName = "All";
    $deviceSearchParameter->Device = new SoapVar(
        $deviceCriterion, SOAP_ENC_OBJECT, 
        'DeviceCriterion', 
        $GLOBALS['AdInsightProxy']->GetNamespace());
    $searchParameters[] = new SoapVar(
        $deviceSearchParameter, 
        SOAP_ENC_OBJECT, 
        'DeviceSearchParameter', 
        $GLOBALS['AdInsightProxy']->GetNamespace());

    // If ExpandIdeas is false, the QuerySearchParameter is required.
    $expandIdeas = true;
    print("-----\r\nGetKeywordIdeas:\r\n");
    $getKeywordIdeasResponse = AdInsightExampleHelper::GetKeywordIdeas(
        $expandIdeas,
        $ideaAttributes,
        $searchParameters
    );
        
    $keywordIdeas = $getKeywordIdeasResponse->KeywordIdeas;

    if(!isset($getKeywordIdeasResponse->KeywordIdeas) || count($keywordIdeas) < 1)
    {
        printf("No keyword ideas are available for the search parameters.\r\n");
        return;
    }
    
    print("KeywordIdeas:\r\n");
    AdInsightExampleHelper::OutputArrayOfKeywordIdea($keywordIdeas);

    // Let's get traffic estimates for each returned keyword idea.

    // The returned ad group ID within each keyword idea will either be null or negative.
    // Negative identifiers can be used to map the keyword ideas into suggested new ad groups. 
    // A null ad group identifier indicates that the keyword idea was sourced from your 
    // keyword idea search parameter.  

    // In this example we will use the suggested ad groups to request traffic estimates.
    // Each of the seed keyword ideas will be submitted in the same ad group estimator.

    $ideaAdGroupIds = array();
    foreach ($keywordIdeas->KeywordIdea as $keywordIdea)
    {
        $ideaAdGroupIds[] = $keywordIdea->AdGroupId;
    }
    $adGroupIds = array_unique($ideaAdGroupIds, SORT_REGULAR);
    $adGroupEstimatorCount = count($adGroupIds);

    // If any ad group IDs are null, traffic estimates for all of those keyword ideas
    // will be submitted via $adGroupEstimators[0]. If none of the ad group IDs are null,
    // then $adGroupEstimators[0] will correspond to keyword ideas where AdGroupId is -1.
    // Each KeywordIdea is assigned to an AdGroupEstimator below.

    $seedOffset = in_array(null, $adGroupIds) ? 0 : 1;
    
    $adGroupEstimators = array();
    for($index = 0; $index < $adGroupEstimatorCount; $index++)
    {
        $adGroupEstimator = new AdGroupEstimator();

        // The AdGroupId is reserved for future use.
        // The traffic estimates are not based on any specific ad group. 
        $adGroupEstimator->AdGroupId = null;
            
        // We will add new keyword estimators while iterating the keyword ideas below.
        $adGroupEstimator->KeywordEstimators = array();

        // Optionally you can set an ad group level max CPC (maximum search bid)
        $adGroupEstimator->MaxCpc = 5.00;

        $adGroupEstimators[] = $adGroupEstimator;
    }

    foreach($keywordIdeas->KeywordIdea as $keywordIdea)
    {
        $keywordEstimator = new KeywordEstimator();
        $keyword = new Keyword();
        // The keyword Id is reserved for future use.
        // The returned estimates are not based on any specific keyword.
        $keyword->Id = null;
        // The match type is required. Exact, Broad, and Phrase are supported.
        $keyword->MatchType = MatchType::Exact;
        // Use the suggested keyword
        $keyword->Text = $keywordIdea->Keyword;
        $keywordEstimator->Keyword = $keyword;
        $keywordEstimator->MaxCpc = $keywordIdea->SuggestedBid > 0.04 ? $keywordIdea->SuggestedBid : null;
        
        $index = ($keywordIdea->AdGroupId != null) ? -($keywordIdea->AdGroupId) - $seedOffset : 0;
        
        $adGroupEstimators[$index]->KeywordEstimators[] = $keywordEstimator;
        
    }

    // Currently you can include only one CampaignEstimator per service call.

    $campaignEstimators = array();
    $campaignEstimator = new CampaignEstimator();
    
    // Let's use the ad group and keyword estimators that were sourced from keyword ideas above.

    $campaignEstimator->AdGroupEstimators = $adGroupEstimators;

    // The CampaignId is reserved for future use.
    // The returned estimates are not based on any specific campaign.

    $campaignEstimator->CampaignId = null;

    $campaignEstimator->DailyBudget = 50.00;

    $campaignEstimator->NegativeKeywords = array();
    $negativeKeyword = new NegativeKeyword();
    $negativeKeyword->Text = "foo";
    $negativeKeyword->MatchType = MatchType::Exact;
    $campaignEstimator->NegativeKeywords[] = $negativeKeyword;

    // The location, language, and network criterions are required for traffic estimates.

    $campaignEstimator->Criteria = array();

    // You must specify between 1 and 100 locations
    $locationSearchParameter->Locations = array();
    $locationCriterion = new LocationCriterion();
    // United States
    $locationCriterion->LocationId = 190;
    $campaignEstimator->Criteria[] = new SoapVar(
        $locationCriterion, 
        SOAP_ENC_OBJECT, 
        'LocationCriterion', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    // You must specify exactly one language criterion
    $languageCriterion = new LanguageCriterion();
    $languageCriterion->Language = "English";
    $campaignEstimator->Criteria[] = new SoapVar(
        $languageCriterion, 
        SOAP_ENC_OBJECT, 
        'LanguageCriterion', 
        $GLOBALS['AdInsightProxy']->GetNamespace());

    // You must specify exactly one network criterion
    $networkSearchParameter = new NetworkSearchParameter();
    $networkCriterion = new NetworkCriterion();
    $networkCriterion->Network = NetworkType::OwnedAndOperatedAndSyndicatedSearch;
    $campaignEstimator->Criteria[] = new SoapVar(
        $networkCriterion, 
        SOAP_ENC_OBJECT, 
        'NetworkCriterion', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    // Optionally you can specify exactly one device.
    // If you do not specify a device, the returned traffic estimates 
    // are aggregated for all devices.
    // The "All" device name is equivalent to omitting the DeviceCriterion.
    $deviceCriterion = new DeviceCriterion();
    $deviceCriterion->DeviceName = "All";
    $campaignEstimator->Criteria[] = new SoapVar(
        $deviceCriterion, 
        SOAP_ENC_OBJECT, 
        'DeviceCriterion', 
        $GLOBALS['AdInsightProxy']->GetNamespace()
    );

    $campaignEstimators[] = $campaignEstimator;
    
    print("-----\r\nGetKeywordTrafficEstimates:\r\n");
    $getKeywordTrafficEstimatesResponse = AdInsightExampleHelper::GetKeywordTrafficEstimates(
        $campaignEstimators
    );
    print("CampaignEstimates:\r\n");
    AdInsightExampleHelper::OutputArrayOfCampaignEstimate($getKeywordTrafficEstimatesResponse->CampaignEstimates);

}
catch (SoapFault $e)
{
    printf("-----\r\nFault Code: %s\r\nFault String: %s\r\nFault Detail: \r\n", $e->faultcode, $e->faultstring);
    var_dump($e->detail);
    print "-----\r\nLast SOAP request/response:\r\n";
    print $GLOBALS['Proxy']->GetWsdl() . "\r\n";
    print $GLOBALS['Proxy']->GetService()->__getLastRequest()."\r\n";
    print $GLOBALS['Proxy']->GetService()->__getLastResponse()."\r\n";
}
catch (Exception $e)
{
    // Ignore fault exceptions that we already caught.
    if ($e->getPrevious())
    { ; }
    else
    {
        print $e->getCode()." ".$e->getMessage()."\n\n";
        print $e->getTraceAsString()."\n\n";
    }
}
from auth_helper import *
from output_helper import *
from adinsight_example_helper import *

# You must provide credentials in auth_helper.py.

def main(authorization_data):

    try:

        # You must specify the attributes that you want in each returned KeywordIdea.

        ideas_attributes=adinsight_service.factory.create('ArrayOfKeywordIdeaAttribute')
        ideas_attributes.KeywordIdeaAttribute.append([
            'AdGroupId',
            'AdGroupName',
            'AdImpressionShare',
            'Competition',
            'Keyword',
            'MonthlySearchCounts',
            'Relevance',
            'Source',
            'SuggestedBid'
        ])

        # Use the GetKeywordIdeaCategories operation to get a list of valid category identifiers.
        # A category identifier will be used in the CategorySearchParameter below.

        output_status_message("-----\nGetKeywordIdeaCategories:")
        getkeywordideacategories_response=adinsight_service.GetKeywordIdeaCategories()
        category_id=getkeywordideacategories_response['KeywordIdeaCategory'][0].CategoryId
        output_status_message("CategoryId {0} will be used in the CategorySearchParameter below".format(category_id))
        
        # Only one of each SearchParameter type can be specified per call.

        search_parameters=adinsight_service.factory.create('ArrayOfSearchParameter')

        # Determines the start and end month for MonthlySearchCounts data returned with each KeywordIdea.
        # The date range search parameter is optional. If you do not include the DateRangeSearchParameter 
        # in the GetKeywordIdeas request, then you will not be able to confirm whether the first list item 
        # within MonthlySearchCounts is data for the previous month, or the month prior. If the date range is 
        # specified and the most recent month's data is not yet available, then GetKeywordIdeas will return an error.

        date_range_search_parameter=adinsight_service.factory.create('DateRangeSearchParameter')
        end_date=adinsight_service.factory.create('DayMonthAndYear')
        end_date.Day=30
        end_date.Month=9
        end_date.Year=2018

        start_date=adinsight_service.factory.create('DayMonthAndYear')
        start_date.Day=1
        start_date.Month=9
        start_date.Year=2018

        date_range_search_parameter.EndDate=end_date
        date_range_search_parameter.StartDate=start_date

        # The CategorySearchParameter corresponds to filling in 'Your product category' under
        # 'Search for new keywords using a phrase, website, or category' in the 
        # Bing Ads web application's Keyword Planner tool.
        # One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.

        category_search_parameter=adinsight_service.factory.create('CategorySearchParameter')
        category_search_parameter.CategoryId=category_id

        # The QuerySearchParameter corresponds to filling in 'Product or service' under
        # 'Search for new keywords using a phrase, website, or category' in the 
        # Bing Ads web application's Keyword Planner tool.
        # One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.
        # When calling GetKeywordIdeas, if ExpandIdeas = false the QuerySearchParameter is required. 

        query_search_parameter=adinsight_service.factory.create('QuerySearchParameter')
        queries=adinsight_service.factory.create('ns1:ArrayOfstring')
        queries.string.append([
            'tennis',
            'tennis shoes',
            'running',
            'running shoes',
            'cross training',
            'running',
        ])
        query_search_parameter.Queries=queries

        # The UrlSearchParameter corresponds to filling in 'Your landing page' under
        # 'Search for new keywords using a phrase, website, or category' in the 
        # Bing Ads web application's Keyword Planner tool.
        # One or more CategorySearchParameter, QuerySearchParameter, or UrlSearchParameter is required.

        url_search_parameter=adinsight_service.factory.create('UrlSearchParameter')
        url_search_parameter.Url='contoso.com'

        # The LanguageSearchParameter, LocationSearchParameter, and NetworkSearchParameter
        # correspond to the 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category' ->
        # 'Targeting' workflow in the Bing Ads web application.
        # Each of these search parameters are required.
        
        language_search_parameter=adinsight_service.factory.create('LanguageSearchParameter')
        languages=adinsight_service.factory.create('ArrayOfLanguageCriterion')
        language=adinsight_service.factory.create('LanguageCriterion')
        # You must specify exactly one language
        language.Language='English'
        languages.LanguageCriterion.append([language])
        language_search_parameter.Languages=languages

        location_search_parameter=adinsight_service.factory.create('LocationSearchParameter')
        locations=adinsight_service.factory.create('ArrayOfLocationCriterion')
        # You must specify between 1 and 100 locations
        location=adinsight_service.factory.create('LocationCriterion')
        # United States
        location.LocationId='190'
        locations.LocationCriterion.append([location])
        location_search_parameter.Locations=locations

        network_search_parameter=adinsight_service.factory.create('NetworkSearchParameter')
        network=adinsight_service.factory.create('NetworkCriterion')
        network.Network='OwnedAndOperatedAndSyndicatedSearch'
        network_search_parameter.Network=network

        # The CompetitionSearchParameter, ExcludeAccountKeywordsSearchParameter, IdeaTextSearchParameter, 
        # ImpressionShareSearchParameter, SearchVolumeSearchParameter, and SuggestedBidSearchParameter  
        # correspond to the 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category' -> 
        # 'Search options' workflow in the Bing Ads web application.
        # Use these options to refine what keywords we suggest. You can limit the keywords by historical data, 
        # hide keywords already in your account, and include or exclude specific keywords.
        # Each of these search parameters are optional.

        competition_search_parameter=adinsight_service.factory.create('CompetitionSearchParameter')
        competition_levels=adinsight_service.factory.create('ArrayOfCompetitionLevel')
        competition_levels.CompetitionLevel.append([
            'High',
            'Medium',
            'Low'])
        competition_search_parameter.CompetitionLevels=competition_levels

        exclude_account_keyword_search_parameter=adinsight_service.factory.create('ExcludeAccountKeywordsSearchParameter')
        exclude_account_keyword_search_parameter.ExcludeAccountKeywords=False

        idea_text_search_parameter=adinsight_service.factory.create('IdeaTextSearchParameter')
        excluded_list=adinsight_service.factory.create('ArrayOfKeyword')
        excluded_keyword1=adinsight_service.factory.create('Keyword')
        # The match type is required. Only Broad is supported.
        excluded_keyword1.MatchType='Broad'
        excluded_keyword1.Text='tennis court'
        excluded_list.Keyword.append([excluded_keyword1])
        excluded_keyword2=adinsight_service.factory.create('Keyword')
        excluded_keyword2.MatchType='Broad'
        excluded_keyword2.Text='tennis pro'
        excluded_list.Keyword.append([excluded_keyword2])

        included_list=adinsight_service.factory.create('ArrayOfKeyword')
        included_keyword1=adinsight_service.factory.create('Keyword')
        included_keyword1.MatchType='Broad'
        included_keyword1.Text='athletic clothing'
        included_list.Keyword.append([included_keyword1])
        included_keyword2=adinsight_service.factory.create('Keyword')
        included_keyword2.MatchType='Broad'
        included_keyword2.Text='athletic shoes'
        included_list.Keyword.append([included_keyword2])

        idea_text_search_parameter.Excluded=excluded_list
        idea_text_search_parameter.Included=included_list

        # Equivalent of '0 <= value <= 50'
        impression_share_search_parameter=adinsight_service.factory.create('ImpressionShareSearchParameter')
        impression_share_search_parameter.Maximum='50'
        impression_share_search_parameter.Minimum='0'

        # Equivalent of 'value >= 50'
        search_volume_search_parameter=adinsight_service.factory.create('SearchVolumeSearchParameter')
        search_volume_search_parameter.Maximum=None
        search_volume_search_parameter.Minimum='50'

        # Equivalent of both 'value <= 50' and '0 <= value <= 50'
        suggested_bid_search_parameter=adinsight_service.factory.create('SuggestedBidSearchParameter')
        suggested_bid_search_parameter.Maximum='50'
        suggested_bid_search_parameter.Minimum=None

        # Setting the device criterion is not available in the 
        # 'Keyword Planner' -> 'Search for new keywords using a phrase, website, or category'
        # workflow in the Bing Ads web application.
        # The DeviceSearchParameter is optional and by default the keyword ideas data
        # are aggregated for all devices.
        
        device_search_parameter=adinsight_service.factory.create('DeviceSearchParameter')
        device=adinsight_service.factory.create('DeviceCriterion')
        # Possible values are All, Computers, Tablets, Smartphones
        device.DeviceName='All'
        device_search_parameter.Device=device

        # Populate ArrayOfSearchParameter
        search_parameters.SearchParameter.append([
            date_range_search_parameter,
            category_search_parameter,
            query_search_parameter,
            url_search_parameter,
            language_search_parameter,
            location_search_parameter,
            network_search_parameter,
            competition_search_parameter,
            exclude_account_keyword_search_parameter,
            idea_text_search_parameter,
            impression_share_search_parameter,
            search_volume_search_parameter,
            suggested_bid_search_parameter,
            device_search_parameter
        ])
        
        # If ExpandIdeas is false, the QuerySearchParameter is required.

        output_status_message("-----\nGetKeywordIdeas:")
        get_keyword_ideas_response=adinsight_service.GetKeywordIdeas(
            IdeaAttributes=ideas_attributes,
            SearchParameters=search_parameters,
            ExpandIdeas=True
        )
        keyword_ideas=get_keyword_ideas_response

        if keyword_ideas is None:
            output_status_message("No keyword ideas are available for the search parameters.")
            sys.exit(0)
        
        output_status_message("KeywordIdeas:")
        output_array_of_keywordidea(keyword_ideas)
        
        # Let's get traffic estimates for each returned keyword idea.

        # The returned ad group ID within each keyword idea will either be null or negative.
        # Negative identifiers can be used to map the keyword ideas into suggested new ad groups. 
        # A null ad group identifier indicates that the keyword idea was sourced from your 
        # keyword idea search parameter.

        # In this example we will use the suggested ad groups to request traffic estimates.
        # Each of the seed keyword ideas will be submitted in the same ad group.

        ad_group_ids=[]
        for keyword_idea in keyword_ideas['KeywordIdea']:
            ad_group_ids.append(keyword_idea.AdGroupId)
        distinct_ad_group_ids=list(set(ad_group_ids))
        ad_group_estimator_count=len(distinct_ad_group_ids)
        seed_offset=0 if distinct_ad_group_ids.__contains__(None) else 1

        ad_group_estimators=adinsight_service.factory.create('ArrayOfAdGroupEstimator')

        for index in range(0, ad_group_estimator_count):
            ad_group_estimator=adinsight_service.factory.create('AdGroupEstimator')
            # The AdGroupId is reserved for future use.
            # The traffic estimates are not based on any specific ad group.
            ad_group_estimator.AdGroupId=None
            # Optionally you can set an ad group level max CPC (maximum search bid)
            ad_group_estimator.MaxCpc='5.00'
            # We will add new keyword estimators while iterating the keyword ideas below.
            ad_group_estimator.KeywordEstimators=adinsight_service.factory.create('ArrayOfKeywordEstimator')
            ad_group_estimators.AdGroupEstimator.append(ad_group_estimator)

        for keyword_idea in keyword_ideas['KeywordIdea']:
            keyword_estimator=adinsight_service.factory.create('KeywordEstimator')
            keyword=adinsight_service.factory.create('Keyword')
            # The keyword Id is reserved for future use.
            # The returned estimates are not based on any specific keyword.
            keyword.Id=None
            # The match type is required. Exact, Broad, and Phrase are supported.
            keyword.MatchType='Exact'
            # Use the suggested keyword.
            keyword.Text=keyword_idea.Keyword
            keyword_estimator.Keyword=keyword
            # Round the suggested bid to two decimal places
            keyword_estimator.MaxCpc = keyword_idea.SuggestedBid if keyword_idea.SuggestedBid > 0.04 else None

            index = (keyword_idea.AdGroupId * -1) - seed_offset if keyword_idea.AdGroupId is not None else 0
            ad_group_estimators['AdGroupEstimator'][index].KeywordEstimators.KeywordEstimator.append(keyword_estimator)
        
        # Currently you can include only one CampaignEstimator per service call.
        campaign_estimators=adinsight_service.factory.create('ArrayOfCampaignEstimator')
        campaign_estimator=adinsight_service.factory.create('CampaignEstimator')
        
        # Let's use the ad group and keyword estimators that were sourced from keyword ideas above.
        campaign_estimator.AdGroupEstimators = ad_group_estimators

        # The CampaignId is reserved for future use.
        # The returned estimates are not based on any specific campaign.
        campaign_estimator.CampaignId = None

        campaign_estimator.DailyBudget = 50.00

        negative_keyword_estimators=adinsight_service.factory.create('ArrayOfKeywordEstimator')
        negative_keywords_list=adinsight_service.factory.create('ArrayOfNegativeKeyword')
        negative_keyword=adinsight_service.factory.create('NegativeKeyword')
        negative_keyword.MatchType='Exact'
        negative_keyword.Text='foo'
        negative_keywords_list.NegativeKeyword.append([negative_keyword])
        negative_keyword_estimators.KeywordEstimator=negative_keywords_list

        campaign_estimator.NegativeKeywords=negative_keyword_estimators

        # The location, language, and network criterions are required for traffic estimates.
        traffic_criteria=adinsight_service.factory.create('ArrayOfCriterion')

        # You must specify between 1 and 100 locations
        traffic_location=adinsight_service.factory.create('LocationCriterion')
        # United States
        traffic_location.LocationId='190'

        # You must specify exactly one language criterion
        traffic_language=adinsight_service.factory.create('LanguageCriterion')
        traffic_language.Language='English'

        # You must specify exactly one network criterion
        traffic_network=adinsight_service.factory.create('NetworkCriterion')
        traffic_network.Network='OwnedAndOperatedAndSyndicatedSearch'

        # Optionally you can specify exactly one device.
        # If you do not specify a device, the returned traffic estimates 
        # are aggregated for all devices.
        # The "All" device name is equivalent to omitting the DeviceCriterion.
        traffic_device=adinsight_service.factory.create('DeviceCriterion')
        traffic_device.DeviceName='All'

        traffic_criteria.Criterion.append([
            traffic_location,
            traffic_language,
            traffic_network,
            traffic_device
        ])
        campaign_estimator.Criteria=traffic_criteria
        campaign_estimators.CampaignEstimator.append(campaign_estimator)

        output_status_message("-----\nGetKeywordTrafficEstimates:")
        get_keyword_traffic_estimates_response=adinsight_service.GetKeywordTrafficEstimates(
            CampaignEstimators=campaign_estimators)
        output_status_message("CampaignEstimates:")
        output_array_of_campaignestimate(get_keyword_traffic_estimates_response)

    except WebFault as ex:
        output_webfault_errors(ex)
    except Exception as ex:
        output_status_message(ex)

# Main execution
if __name__ == '__main__':

    print("Loading the web service client proxies...")
    
    authorization_data=AuthorizationData(
        account_id=None,
        customer_id=None,
        developer_token=DEVELOPER_TOKEN,
        authentication=None,
    )

    adinsight_service=ServiceClient(
        service='AdInsightService',
        authorization_data=authorization_data,
        environment=ENVIRONMENT,
        version=13
    )

    print(adinsight_service.soap_client)

    authenticate(authorization_data)
        
    main(authorization_data)

See Also

Get Started with the Bing Ads API