proximityTargets using python

39 views
Skip to first unread message

david

unread,
Jul 7, 2008, 4:38:22 PM7/7/08
to AdWords API Forum
Hi,

I am trying to set proximity targets using python
(awapi_python_lib_1.1.0, api version 1.2).

If you look at the examples, they have something like this for the
geoTargeting element of the monster campaign arg:

'geoTargeting': {
'cityTargets': ['New York, NY US'],
'countryTargets': ['US'],
'metroTargets': ['501'],
'proximityTargets': [
{
'latitudeMicroDegrees': '12345',
'longitudeMicroDegrees': '12345',
'radiusMeters': '5'
}
],
'regionTargets': ['US-NY'],
'targetAll': 'False'
},

When I try something like this, I get an error:

lib.Errors.Error: Error: faultcode: soapenv:Server.userException
faultstring: org.xml.sax.SAXException: Invalid element in
com.google.ads.netapi.services.datamodel.ProximityTargets -
radiusMeters


I notice that in the sample, they do not mention "circles". If you
look at the xml when reading an existing campaign with proximity
targets, you get something like:

<ns1:geoTargeting>
<ns1:targetAll>false</ns1:targetAll>
<ns1:countryTargets xsi:null="true"/>
<ns1:regionTargets xsi:null="true"/>
<ns1:metroTargets xsi:null="true"/>
<ns1:cityTargets xsi:null="true"/>
<ns1:proximityTargets>
<ns1:circles>
<ns1:longitudeMicroDegrees>-77261388</
ns1:longitudeMicroDegrees>
<ns1:latitudeMicroDegrees>38855000</ns1:latitudeMicroDegrees>
<ns1:radiusMeters>128748</ns1:radiusMeters>
</ns1:circles>
</ns1:proximityTargets>
</ns1:geoTargeting>
<ns1:id>7239937</ns1:id>

Any ideas on what is wrong?

Thank you!

David

AdWords API Advisor

unread,
Jul 7, 2008, 5:43:37 PM7/7/08
to AdWords API Forum
Hello David,

The minimum radius for a circle target is 1000 meters (i.e. 1
kilometer). Specifying 5 meters would lead to the error you're seeing.
(I have a longstanding request in with the documentation team to get
that information added to http://www.google.com/apis/adwords/developer/Circle.html)

Could you point me to the sample code which you were using? I'll look
into getting that updated.

Cheers,
-Jeff Posnick, AdWords API Team

david

unread,
Jul 7, 2008, 6:01:26 PM7/7/08
to AdWords API Forum
Hi Jeff -

No, I am not using the value '5' (that was from the sample). Here is
exactly what I am using:

cam_geo_test = {
'status': 'Paused',
'name': 'ccxx_geo',
'networkTargeting': ['ContentNetwork'],
'languageTargeting': ['en'],
'geoTargeting': {
'cityTargets': ['Flushing, NY US'],
'proximityTargets': [
{
'radiusMeters': '9656',
'longitudeMicroDegrees': '-73830030',
'latitudeMicroDegrees': '40763600'
}
],
},
'dailyBudget': '2000000'
}

status = campaign_service.AddCampaign(cam_geo_test)

On Jul 7, 5:43 pm, AdWords API Advisor <adwordsapiadvi...@google.com>
wrote:
> Hello David,
>
> The minimum radius for a circle target is 1000 meters (i.e. 1
> kilometer). Specifying 5 meters would lead to the error you're seeing.
> (I have a longstanding request in with the documentation team to get
> that information added tohttp://www.google.com/apis/adwords/developer/Circle.html)

david

unread,
Jul 8, 2008, 10:32:48 AM7/8/08
to AdWords API Forum
So, I am still wondering - is there a bug in my code? Or in the
documentation? Or in the Python api itself?

How does one do proximity targeting using Python?

Thanks!
Message has been deleted

AdWords API Advisor

unread,
Jul 8, 2008, 4:15:11 PM7/8/08
to AdWords API Forum
Hello David,

Thanks, I see the samples that you're basing your code on now. I do
think, as you imply above, that the problem is a missing 'circles'
dict key in the Python structure being passed to the API. Could you
try something like (currently untested on my end):

'proximityTargets': {
'circles': [
{
'radiusMeters': '9656',
'longitudeMicroDegrees': '-73830030',
'latitudeMicroDegrees': '40763600'
}
]
},

I've informed my colleague who maintains the Python client library
about the error in the sample code, and it should be resolved in the
next release. Apologies for the inconvenience in the meantime.

Cheers,
-Jeff Posnick, AdWords API Team


david

unread,
Jul 8, 2008, 5:50:30 PM7/8/08
to AdWords API Forum
No, Jeff. That doesn't work.

Is there any way for your colleague who maintains the library to send
me the fix when he has it done? You see, I have a number of campaigns
whose geotargeting details I would like to copy into new campaigns. I
know there are a lot of ways of doing this, but using the current
Python library at the moment would be the easiest...

Thanks!

David

On Jul 8, 4:15 pm, AdWords API Advisor <adwordsapiadvi...@google.com>

david

unread,
Jul 9, 2008, 6:51:45 AM7/9/08
to AdWords API Forum
I just created a fix for the Google Python code for this, if anyone is
interested.

AdWords API Advisor

unread,
Jul 9, 2008, 12:19:54 PM7/9/08
to AdWords API Forum
I'm passing this on from my colleague. Is this approach similar to
what you ended up doing? It should make it into the official Python
client library release.

==================================================
I've tested this with SOAPpy and it works just fine. Campaign object
should look something like below. In SanityCheck.py, he will need to
replace ValidateGeoTarget function with the new version below.

campaign = {
'dailyBudget': '1000000',
'enableSeparateContentBids': 'False',
'geoTargeting': {
'proximityTargets': {
'circles': [
{
'latitudeMicroDegrees': '40763600',
'longitudeMicroDegrees': '-73830030',
'radiusMeters': '9656'
}
]
},
},
'languageTargeting': ['en'],
'networkTargeting': ['GoogleSearch', 'SearchNetwork'],
'status': 'Paused'
}


def ValidateGeoTarget(geo_target):
"""Validate GeoTarget object.

Args:
geo_target: dict geographic targeting rules for this entity.

Returns:
str geographic targeting converted into str type.
"""

SanityCheck.ValidateTypes(((geo_target, dict),))
targeting = ''
for key in geo_target:
if key == 'targetAll':
SanityCheck.ValidateTypes(((geo_target[key], str),))
targeting += '<%s>%s</%s>' % (key, geo_target[key], key)
elif key == 'cityTargets':
SanityCheck.ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
SanityCheck.ValidateTypes(((item, str),))
targeting += '<cities>%s</cities>' % item
targeting += '</%s>' % key
elif key == 'countryTargets':
SanityCheck.ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
SanityCheck.ValidateTypes(((item, str),))
targeting += '<countries>%s</countries>' % item
targeting += '</%s>' % key
elif key == 'metroTargets':
SanityCheck.ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
SanityCheck.ValidateTypes(((item, str),))
targeting += '<metros>%s</metros>' % item
targeting += '</%s>' % key
elif key == 'regionTargets':
SanityCheck.ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
SanityCheck.ValidateTypes(((item, str),))
targeting += '<regions>%s</regions>' % item
targeting += '</%s>' % key
elif key == 'proximityTargets':
SanityCheck.ValidateTypes(((geo_target[key], dict),))
targeting += '<%s>' % key
for sub_key in geo_target[key]:
targeting += '<%s>' % sub_key
SanityCheck.ValidateTypes(((geo_target[key][sub_key], list),))
for item in geo_target[key][sub_key]:
SanityCheck.ValidateTypes(((item, dict),))
for sub_sub_key in item:
SanityCheck.ValidateTypes(((item[sub_sub_key], str),))
targeting += '<%s>%s</%s>' % (sub_sub_key,
item[sub_sub_key], sub_sub_key)
targeting += '</%s>' % sub_key
targeting += '</%s>' % key
else:
pass

return targeting
===========================================

david

unread,
Jul 9, 2008, 2:58:50 PM7/9/08
to AdWords API Forum
Yes, mine is very similar. The main difference is that my
'proximityTargets' points to a list, rather than a dict. This would
allow multiple 'circles' to go in - one of our campaigns has this
(which were manually entered and the xml shows it when GetCampaign()
is called, but don't yet know if it will work in AddCampaign() or
UpdateCampaign()).

One point - I don't think the API is very clear about "circles" - for
instance, why isn't it called "circle"? "circles", to me, would be a
list of circles, and logically you'd have

proximityTargets
circles
circle
circle
...

with the possibility of other types of proximityTargets beyond
"circle".

But the way the API currently works, it seems, is:

proximityTargets
circles
circles
...



my campaign descriptor
--------------------------------------
cam_geo_test2 = {
'status': 'Paused',
'name': 'cabc',
'networkTargeting': ['ContentNetwork'],
'languageTargeting': ['en'],
'geoTargeting': {
'cityTargets': ['Flushing, NY US'],
'proximityTargets': [
{ 'circles': [
{
'longitudeMicroDegrees': '-73830030',
'latitudeMicroDegrees': '40763600',
'radiusMeters': '9656',
}
]
}]
},
'budgetAmount': '5000000',
'budgetPeriod': 'Daily',
}
-------------------------------------------------
def ValidateGeoTarget(geo_target):
"""Validate GeoTarget object.

Args:
geo_target: dict geographic targeting rules for this entity.

Returns:
str geographic targeting converted into str type.
"""

ValidateTypes(((geo_target, dict),))
targeting = ''
for key in geo_target:
if key == 'targetAll':
ValidateTypes(((geo_target[key], str),))
targeting += '<%s>%s</%s>' % (key, geo_target[key], key)
elif key == 'cityTargets':
ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
ValidateTypes(((item, str),))
targeting += '<cities>%s</cities>' % item
targeting += '</%s>' % key
elif key == 'countryTargets':
ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
ValidateTypes(((item, str),))
targeting += '<countries>%s</countries>' % item
targeting += '</%s>' % key
elif key == 'metroTargets':
ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
ValidateTypes(((item, str),))
targeting += '<metros>%s</metros>' % item
targeting += '</%s>' % key
elif key == 'regionTargets':
ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
ValidateTypes(((item, str),))
targeting += '<regions>%s</regions>' % item
targeting += '</%s>' % key
elif key == 'proximityTargets':
ValidateTypes(((geo_target[key], list),))
targeting += '<%s>' % key
for item in geo_target[key]:
ValidateTypes(((item, dict),))
for sub_key in item:
if sub_key == 'circles':
ValidateTypes(((item[sub_key],list),))
for item1 in item[sub_key]:
ValidateTypes(((item1, dict),))
targeting += '<circles>'
for sub_sub_key in item1:
targeting += '<%s>%s</%s>' % (sub_sub_key,
item1[sub_sub_key], sub_sub_key)
targeting += '</circles>'

targeting += '</%s>' % key
else:
pass

return targeting
---------------------------------------------------------------


On Jul 9, 12:19 pm, AdWords API Advisor <adwordsapiadvi...@google.com>

AdWords API Advisor

unread,
Jul 9, 2008, 4:28:51 PM7/9/08
to AdWords API Forum
Hello David,

The convention of pluralizing elements that may occur more than once,
rather than wrapping singular elements in a pluralized container
element, is found throughout the AdWords API (see, for instance, the
'ads' parameter to addAds()). I can't say what the initial rationale
for this was, and it can get somewhat confusing when you only plan on
including one instance of the parameter in your SOAP call.

I do think that the change my colleague proposes making will support
for multiple circles parameters, by passing in multiple anonymous
dicts in the array that the 'circles' key refers to. I'm assuming he
implemented it that way to keep it consistent with how other array
parameters are handled elsewhere in the code, but if you need
clarification on that I can ask him.

Cheers,
-Jeff Posnick, AdWords API Team


> ...
>
> read more »

david

unread,
Jul 10, 2008, 1:57:45 PM7/10/08
to AdWords API Forum
Great. I'll do it his way. Thank you.

On Jul 9, 4:28 pm, AdWords API Advisor <adwordsapiadvi...@google.com>
> ...
>
> read more »

david

unread,
Jul 10, 2008, 2:28:50 PM7/10/08
to AdWords API Forum
Whoops. Ok, I just tried multiple circles like so:

cam_geo_test3 = {
'status': 'Paused',
'name': 'c4d2',
'networkTargeting': ['ContentNetwork'],
'languageTargeting': ['en'],
'geoTargeting': {
'cityTargets': ['Flushing, NY US'],
'proximityTargets': {
'circles': [
{
'longitudeMicroDegrees': '-73830030',
'latitudeMicroDegrees': '40763600',
'radiusMeters': '9656',
},
{
'longitudeMicroDegrees': '-80073749',
'latitudeMicroDegrees': '34375020',
'radiusMeters': '1656',
}

]
},
},
'id' : '22xxx1603',

'budgetAmount': '5000000',
'budgetPeriod': 'Daily',
}

This is how I presume you meant for this to work. However, the
resulting xml is apparently incorrect - (I'm showing the geoTargeting
element only, from log:)

<geoTargeting><cityTargets><cities>Flushing, NY US</cities></
cityTargets><proximityTargets><circles>
<radiusMeters>19656</radiusMeters><longitudeMicroDegrees>-73830030</
longitudeMicroDegrees><latitudeMicroDegrees>40763600</
latitudeMicroDegrees>
</circles></proximityTargets></geoTargeting>

As you can see, there is only a single <circles> inside the
<proximityTargets>, but there should be one for each separate circle
set. That is what you get when you do a GetCampaign(),
as you can see from my logs for a campaign with multiple targets:
<ns54:proximityTargets>
<ns54:circles>
<ns54:longitudeMicroDegrees>-80073749</
ns54:longitudeMicroDegrees>
<ns54:latitudeMicroDegrees>34375020</ns54:latitudeMicroDegrees>
<ns54:radiusMeters>32186</ns54:radiusMeters>
</ns54:circles>
<ns54:circles>
<ns54:longitudeMicroDegrees>-79753630</
ns54:longitudeMicroDegrees>
<ns54:latitudeMicroDegrees>33872130</ns54:latitudeMicroDegrees>
<ns54:radiusMeters>32186</ns54:radiusMeters>
</ns54:circles>
<ns54:circles>
<ns54:longitudeMicroDegrees>-79768410</
ns54:longitudeMicroDegrees>
<ns54:latitudeMicroDegrees>34193639</ns54:latitudeMicroDegrees>
<ns54:radiusMeters>32186</ns54:radiusMeters>
</ns54:circles>
</ns54:proximityTargets>
> ...
>
> read more »

AdWords API Advisor

unread,
Jul 10, 2008, 4:33:03 PM7/10/08
to AdWords API Forum
Hi David,

Yep, you found another minor bug ;) The delimiters for defining a
circle should be taken inside the for loop. Replace proximityTargets
snippet of SanityCheck.py with,

elif key == 'proximityTargets':
SanityCheck.ValidateTypes(((geo_target[key], dict),))
targeting += '<%s>' % key
for sub_key in geo_target[key]:
SanityCheck.ValidateTypes(((geo_target[key][sub_key], list),))
for item in geo_target[key][sub_key]:
targeting += '<%s>' % sub_key
SanityCheck.ValidateTypes(((item, dict),))
for sub_sub_key in item:
SanityCheck.ValidateTypes(((item[sub_sub_key], str),))
targeting += '<%s>%s</%s>' % (sub_sub_key,
item[sub_sub_key], sub_sub_key)
targeting += '</%s>' % sub_key
targeting += '</%s>' % key

--Stan
> ...
>
> read more »

david

unread,
Jul 12, 2008, 11:30:30 AM7/12/08
to AdWords API Forum
Thanks, Stan!

On Jul 10, 4:33 pm, AdWords API Advisor <adwordsapiadvi...@google.com>
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages