내부 미디에이션은 공개적으로 제공되지 않습니다.
현재 Audience Network를 사용한 내부 입찰은 비공개 베타이고 공개적으로 제공되지 않습니다. 변경 사항이 있을 경우 추가적인 업데이트를 제공하겠습니다.
또는 Facebook과 파트너를 맺은 미디에이션 플랫폼 중 하나를 통해 Audience Network Bidding에 액세스할 수 있습니다.
이 가이드에서는 자체 경매 서버를 빌드하는 방법을 설명합니다. 아래의 단계별 가이드에서는 전면 광고에서의 입찰 예시를 사용합니다. Audience Network 전면 광고에 대해 이미 잘 알고 있는지 확인하세요. 입찰은 네이티브, 배너, 전면, 인스트림 동영상 및 보상형 동영상 형식도 지원합니다. 아래의 지원되는 광고 형식을 참조하여 여러 광고 형식을 통합할 수 있습니다.
이 샘플 코드는 입찰 API의 작동 원리와 이를 자체 경매 서버에 통합하는 방법을 보여주기 위한 목적으로만 제공됩니다. 샘플 경매 서버는 Flask를 사용한 Python으로 작성되었습니다. 소스 코드를 간결하게 유지하기 위해 안정성과 보안은 최소한으로 고려하였습니다.
ORTB 필드 imp.tagid
에는 인벤토리의 Audience Network ID가 있습니다. 인벤토리는 Audience Network에서 ID로 나타납니다.
Audience Network 입찰 엔드포인트로 전송되는 ORTB 요청에는 기기와 앱 정보가 포함되어야 합니다. 다음은 ORTB 요청의 샘플 페이로드입니다.
{ // Device information from client side 'device': { 'ifa': '${DEVICE_ID}', 'dnt': '0', 'ip': '127.0.0.1' }, // Application information 'app': { 'ver': '1.0', 'bundle': 'com.facebook.audiencenetwork.AdUnitsSample', 'publisher': { // For server to server bidding integration, this is your application id on Facebook 'id': '${APP_ID}', } }, // Placement information we can store on server 'imp': [ { 'id': 'banner_test_bid_req_id', // This is the placement id for Audience Network 'tagid': '${PLACEMENT_ID}', 'banner': { 'w': -1, 'h': 50, }, }, ], // Optional regulations object from client side 'regs': { 'coppa': 0, }, // In server to server integration, you can use the Facebook app id as platform id here 'ext': { 'platformid': '${PLATFORM_ID}', // Mediation partner Platform ID or publisher FB app ID, mandatory. 'authentication_id': '${AUTHENTICATION_ID}', // Authentication token to validate the originator of the request. 'security_app_id': '${AN_SECURITY_APP_MY_SECURITY_APP_ID}', // Security app id used to generate authentication_id. 's2s_version': '${VERSION_NUMBER}', // Version of the integration. Max 16 characters. }, // buyeruid is the user bidder token generated on client side, using the `getBidderToken` method from the Audience Network SDK. // It's constant through out app session so you could cache it on the client side 'user': { 'buyeruid': 'mybuyeruid', }, // Test mode flag 'test': '1', // Time out setting we can store on server 'tmax': 1000, // Request ID we can generate on server 'id': 'banner_test_bid_req_id', // Auction setting we can store on server 'at': 1, }
매개변수 | 유형 | 사용 방법 |
---|---|---|
|
| 미디에이션 파트너인 경우 Facebook 연락처에서 제공한 파트너 ID입니다. |
내부 솔루션을 통합하는 퍼블리셔인 경우 입찰 요청을 보낼 앱 ID입니다. 노출 위치 ID에서 밑줄 앞에 위치하는 첫 부분입니다. | ||
|
| 요청을 보낸 사람을 확인하기 위한 인증 토큰입니다. 이 페이지를 참조하세요. |
|
| authentication_id를 생성하는 데 사용되는 보안 앱 ID입니다. 이 페이지를 참조하세요. |
|
| 통합의 버전입니다. 최대 16자이며, 퍼블리셔가 생성합니다. |
위의 ORTB 요청 페이로드는 Audience Network에 필요합니다. 그러나 자체 경매 서버에서 일부 앱 사양(예: 앱 ID, 노출 위치 ID)과 서버 구성의 일부 다른 매개변수를 정의할 수 있습니다. 그러면 클라이언트 측 앱은 단순화된 요청만 전송하면 됩니다. 서버는 노출 위치 정보를 검색하여 최종 ORTB 요청을 구성할 수 있습니다. 다음은 샘플 경매 서버 설정입니다.
{ "bidding_source_platforms": [ { "platform_name": "audience_network", "end_point": "https://an.facebook.com/${PLATFORM_ID}/placementbid.ortb", "timeout": 1000, "timeout_notification_url": "https://www.facebook.com/audiencenetwork/nurl/?partner=${PARTNER_FBID}&app=${APP_FBID}&auction=${AUCTION_ID}&ortb_loss_code=2" } ], "apps": [ { "app_id": "101", "app_name": "My example app", "placements": [ { "placement_id": "1", "placement_name": "My example placement", "ad_format": "interstitial", "bidding_source_placement_ids":[ { "platform_name": "audience_network", "platform_app_id": "${APP_ID}", "platform_placement_id": "${PLACEMENT_ID}" } ] } ] } ] }
매개변수 | 사용 방법 |
---|---|
| 미디에이션 파트너인 경우 Facebook 연락처에서 제공한 파트너 ID입니다. |
내부 솔루션을 통합하는 퍼블리셔인 경우 입찰 요청을 보낼 앱 ID입니다. 노출 위치 ID에서 밑줄 앞에 위치하는 첫 부분입니다. |
위와 같이 경매 서버를 설정하면 클라이언트 측은 "app_id":"101"
과 "placement_id":"1"
을 포함한 단순화된 요청을 서버로 보내기만 하면 됩니다. 그러면 서버에서 placement_id
, ad_format
, platform_name
등과 같은 전체 노출 위치 정보를 검색할 수 있습니다. 다음은 클라이언트 측의 단순화된 샘플 요청 페이로드입니다.
{ // App ID and placement ID are used to look up settings from // server settings 'app_id': '101', 'placement_id': '1', 'bundle': 'com.facebook.samples.s2sbiddingclient', 'bundle_version': '1.0', // Device specifics 'ifa': '${DEVICE_ID}', 'coppa': 0, 'dnt': 0, // buyer_tokens are the user tokens required for different networks 'buyer_tokens': { // Token for audience network from BidderTokenProvider.getBidderToken(context) // This can be cached for the same app session 'audience_network': 'my-buyeruid', }, }
단순화된 요청을 경매 서버로 보내고 나면 경매 서버 설정에서 app_id
와 placement_id
로 전체 노출 위치, 기기 및 앱 정보를 조회할 수 있습니다. 다음은 샘플 검색 결과입니다.
{ "placement_id": "1", "placement_name": "My example placement", "ad_format": "interstitial", "bidding_source_placement_ids": [{ "platform_name": "audience_network", "platform_app_id": "${APP_ID}", "platform_placement_id": "${PLACEMENT_ID}" }] }
경매 서버가 경매 요청을 받고 나면 각 수요 소스에 대해 입찰 요청을 구성해야 합니다. 다음은 경매 요청을 수신하기 위한 app.py
의 엔드포인트입니다.
@app.route('/get_bid', methods=['POST']) def get_bid(): ''' The actual endpoint that expects a ClientRequest in the parameters ''' # Initialize the server settings ServerSettings.initialize( app.config['bidding_source_platforms'], app.config['apps'] ) request_params = request.get_json(force=True) # See the code sample below for this function in `bid_manager.py` (code, response) = get_bid_response( request.remote_addr, request.user_agent.string, request_params) app.logger.debug('server response: {0} {1}'.format(code, response)) return Response( json.dumps(response), status=code, mimetype='application/json' )
bid_manager.py
에서 클라이언트의 경매 요청에는 app_id
와 placement_id
가 포함됩니다. 이는 서버 설정에서 전체 노출 위치 정보를 검색하는 데 사용됩니다.
# Return Auction Result - Winner - back to client side def get_bid_response(ip, user_agent, request_params): """Get the winner bid response for the current request""" try: app_id = request_params['app_id'] placement_id = request_params['placement_id'] auction_id = get_auction_id() ... # Find placement in the settings placement = ServerSettings.get_placement(app_id, placement_id) # Collect bid requests for different platforms bid_requests = get_bid_requests( ip, user_agent, auction_id, placement, request_params) except Exception as e: raise ParameterError("Error in request parameters: {}".format(str(e))) ... return final_response # Get all bid requests for different platforms def get_bid_requests(ip, user_agent, auction_id, placement, request_params): """Create bid requests based on the internal placement setting""" ... (end_point, data, timeout_notification_url) = get_bid_request( ip, user_agent, auction_id, platform_name, platform_app_id, platform_placement_id, ad_format, request_params) if data is not None: results.append({ 'platform_name': platform_name, 'end_point': end_point, 'data': data, 'timeout_notification_url': timeout_notification_url, }) # current_app.logger.debug("requests: {}".format(results)) return results # Get bid request for each platform def get_bid_request( ip, user_agent, auction_id, platform_name, platform_app_id, platform_placement_id, ad_format, request_params ): """Create bid request for a specific platform""" if platform_name == 'audience_network': return audience_network.get_bid_request( ip, user_agent, auction_id, platform_app_id, platform_placement_id, ad_format, request_params) else: return (None, None, None)
그런 다음 audience_network.py
에서 get_bid_request
함수가 전체 노출 위치 정보에 기초해 Audience Network에 대한 최종 ORTB 요청을 생성합니다.
ORTB 필드 imp.tagid
에는 인벤토리의 Audience Network ID가 있습니다. 인벤토리는 Audience Network에서 노출 위치 ID로 나타납니다.
def get_bid_request( ip, user_agent, auction_id, platform_app_id, platform_placement_id, ad_format, request_params ): ''' Gather the required bid request parameters for networks. The parameters consist of platform settings like app id, placement ids, ad sizes etc., and client side information such as device information, user agent etc. We use the `settings.json` file to store platform specific settings, and the client request to retrieve the clietn specific information. ''' platform = ServerSettings.get_platform('audience_network') end_point = platform['end_point'] timeout = platform['timeout'] timeout_notification_url = platform['timeout_notification_url'] timeout_notification_url.replace('${PARTNER_FBID}', platform_app_id) timeout_notification_url.replace('${APP_FBID}', platform_app_id) timeout_notification_url.replace('${AUCTION_ID}', auction_id) imp = [] if ad_format == 'native': imp.append({ 'id': auction_id, 'native': { 'w': -1, 'h': -1, }, 'tagid': platform_placement_id, }) elif ad_format == 'banner': imp.append({ 'id': auction_id, 'banner': { 'w': -1, 'h': 50, }, 'tagid': platform_placement_id, }) elif ad_format == 'interstitial': imp.append({ 'id': auction_id, 'banner': { 'w': 0, 'h': 0, }, 'tagid': platform_placement_id, 'instl': 1, }) elif ad_format == 'rewarded_video': imp.append({ 'id': auction_id, 'video': { 'w': 0, 'h': 0, 'linearity': 2, }, 'tagid': platform_placement_id, }) elif ad_format == 'instream_video': imp.append({ 'id': auction_id, 'video': { 'w': 0, 'h': 0, 'linearity': 1, }, 'tagid': platform_placement_id, }) else: raise ParameterError("Incorrect ad format") typed_ip = ipaddress.ip_address(ip) device = { 'ifa': request_params['ifa'], 'ua': user_agent, 'dnt': request_params['dnt'], } if type(typed_ip) is ipaddress.IPv6Address: device['ipv6'] = ip else: device['ip'] = ip # Construct the ORTB request request = { 'id': auction_id, 'imp': imp, 'app': { 'bundle': request_params['bundle'], 'ver': request_params['bundle_version'], 'publisher': { 'id': platform_app_id, } }, 'device': device, 'regs': { 'coppa': request_params['coppa'], }, 'user': { 'buyeruid': request_params['buyer_tokens']['audience_network'], }, 'ext': { ' ': platform_app_id, }, 'at': 1, 'tmax': timeout, 'test': request_params['test'], } return (end_point, request, timeout_notification_url)
현재 OpenRTB를 통해 요청할 수 있는 네 가지 유형의 광고를 지원합니다. 여기에는 배너, 네이티브(네이티브 또는 네이티브 배너), 동영상(보상형 또는 인스트림 동영상)과 전면 광고가 있습니다. 참고: 배너, 네이티브 및 동영상 개체는 동시에 선택할 수 없지만 그중 하나는 필수로 포함해야 합니다.
입찰 요청에서 지원되는 광고 형식의 리스트는 다음과 같습니다.
광고 형식 | 입찰 요청의 매개변수 |
---|---|
네이티브 |
|
네이티브 배너 |
|
전면 광고 |
|
보상형 동영상 |
|
보상형 전면 광고 |
|
배너 - 높이: 50 |
|
배너 - 높이: 250* |
|
*이 광고 형식은 수익 관리자에서 배너 또는 중간 직사각형 노출 위치를 만들 수 있습니다.
위와 같이 ORTB 요청 개체가 생성되고 나면 HTTP 요청, post
및 Content-Type: application/json
을 사용하여 http://an.facebook.com/placementbid.ortb
에서 Audience Network 엔드포인트로 요청을 전송할 수 있습니다.
bid_manager.py
에서 각 플랫폼에 대해 모든 입찰 요청을 수집하고 나면 각 플랫폼에 대해 exec_bid_requests를 호출합니다.
# Return Auction Result - Winner - back to client side def get_bid_response(ip, user_agent, request_params): """Get the winner bid response for the current request""" ... # Execute bid requests by network bid_responses = [] for bid_request in bid_requests: (code, response) = exec_bid_request( bid_request['platform_name'], bid_request['end_point'], bid_request['data'], bid_request['timeout_notification_url']) bid_responses.append({ 'platform_name': bid_request['platform_name'], 'code': code, 'response': response, }) final_response = run_auction(bid_responses, placement) return final_response # Execute bid request for different platform (network) def exec_bid_request( platform_name, end_point, request_params, timeout_notification_url ): ''' Actually run the bid requests for the networks. ''' if platform_name == 'audience_network': return audience_network.exec_bid_request( end_point, request_params, timeout_notification_url, ) else: raise InternalError("Invalid platform: {}".format(platform_name))
(입찰 및 입찰 없음 쪽에서 모두) 문제 해결에 유용한 정보를 포함하도록 다음과 같은 응답의 HTTP 헤더를 설정하고 경매 서버에 기록해야 합니다.
X-FB-AN-Request-ID
: 요청 ID는 Audience Network가 각 요청을 디버깅하는 데 필요합니다. 지원을 요청할 때는 항상 이 ID를 캡처하세요.X-FB-AN-Errors
: 발생한 오류 리스트이며 입찰이 없는 이유를 이해하는 데 유용합니다.X-FB-Debug
: Audience Network에서 문제 해결을 위해 담당 직원에게 전송할 수 있는 요청 관련 일부 디버그 정보입니다.참고: 대기 시간을 최소화하기 위해 반드시X-FB-Pool-Routing-Token
헤더를 입찰 요청에 추가해야 합니다.
X-FB-Pool-Routing-Token
: 이 토큰은 가장 가까운 데이터 센터로 요청의 경로를 지정하는 데 사용하며, 그 값은 user.buyeruid
와 동일합니다. audience_network.py
에서 ORTB 요청이 Audience Network로 전송되고 그에 따라 입찰 응답이 경매 서버로 전달됩니다.
def exec_bid_request( end_point, request_params, timeout_notification_url ): try: platform = ServerSettings.get_platform('audience_network') headers = { 'Content-Type': 'application/json; charset=utf-8', 'X-FB-Pool-Routing-Token': request_params['user']['buyeruid'], } timeout = platform['timeout'] r = requests.post( end_point, json=request_params, headers=headers, # Timeout in settings.json in ms timeout=(timeout / 1000), ) except Exception as e: current_app.logger.error(BID_TIMEOUT) # Send time out notification r = requests.get(timeout_notification_url, timeout) return (500, BID_TIMEOUT) if r.status_code == requests.codes.ok: try: data = json.loads(r.text) current_app.logger.debug('Audience Network response: {}'.format( data )) # Parse response from Audience Network with the ORTBResponse ortb_response = ORTBResponse(data) except Exception as e: current_app.logger.error( PARSE_ERROR + "{}".format(e) ) return (500, PARSE_ERROR + "{}".format(e)) return (r.status_code, ortb_response) else: # The error message is stored in the X-FB-AN-Errors header error_header = r.headers.get('x-fb-an-errors') debug_header = r.headers.get('x-fb-debug') bid_request_id = r.headers.get('x-fb-an-request-id') if r.status_code == 400: error_message = INVALID_BID + error_header + INVALID_BID_ADVICE elif r.status_code == 204: error_message = NO_BID + error_header else: error_message = UNEXPECTED_ERROR # Log error information for debugging error = { 'bid_request_id': bid_request_id, 'debug_header': debug_header, 'error_message': error_message, } current_app.logger.error(error) # Respond error status code to client return (r.status_code, error_message)
요청에 Content-Encoding:gzip
헤더를 제공하는 경우 gzip으로 압축한 바이너리 요청 본문을 전달할 수 있습니다.
이제 각 플랫폼(네트워크)에서 입찰 응답을 수신한 상태입니다. bid_manager.py
에서 get_bid_response
함수가 정보가 채워진 입찰 응답을 비교하고 가장 높은 입찰가(낙찰자)를 결정합니다.
def get_bid_response(ip, user_agent, request_params): """Get the winner bid response for the current request""" ... final_response = run_auction(bid_responses, placement) return final_response def run_auction(bid_responses, placement): """Run auction based on raw responses and create the response object""" other_bid = 1 response = (204, None) # default is 204 no fill for bid_response in bid_responses: if bid_response['platform_name'] == 'audience_network': if bid_response['code'] == 200: ortb_response = bid_response['response'] if ortb_response.price > other_bid: response = create_response(bid_response, placement) current_app.logger.debug( 'Audience Network bid: {} won!'.format( ortb_response.price ) ) notify_result(bid_response) else: current_app.logger.debug( 'Audience Network bid: {} lost!'.format( ortb_response.price ) ) notify_result(bid_response, 102) else: current_app.logger.debug(bid_response['response']) return response
이 샘플에서는 Audience Network가 유일한 입찰자이므로 경매 실행 메서드는 단순히 일부 가격 값으로 반환된 입찰을 비교하고 경매에 낙찰되는지 결정합니다. 그러므로 Audience Network에서 반환된 입찰가가 1달러보다 높으면 Audience Network가 낙찰된 것처럼 응답합니다. 그렇지 않으면 경매에 실패한 것으로 간주합니다.
ORTB에 정의된 적절한 실패 코드를 포함하여 반드시낙찰, 실패, 청구 가능 및 시간 초과 알림이 필요합니다. ORTB nurl, lurl 및 burl은 입찰 응답에서 제공됩니다. 입찰 응답 예시는 이전 섹션을 참조하세요. 입찰 시간 초과일 경우 대체 보고 경로를 제공합니다.
입찰 응답에서 낙찰 nurl이 제공됩니다. nurl에서 결제 가격을 채워야 합니다.
"https://www.facebook.com/audiencenetwork/nurl/?partner=${PARTNER_FBID}&app=${APP_FBID}&placement=${PLACEMENT_FBID}&auction=${AUCTION_ID}&impression=${IMPRESSION_ID}&request=${BID_REQUEST_ID}&bid=${BID_ID}&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}"
${AUCTION_PRICE}
: 이는 입찰가와 동일한 단위(예: CPM 기준 USD)를 사용하여 경매의 결제 가격으로 대체해야 합니다.실패 lurl에는 채워야 하는 2개의 플래그가 포함되어 있습니다.
"https://www.facebook.com/audiencenetwork/nurl/?partner=${PARTNER_FBID}&app=${APP_FBID}&placement=${PLACEMENT_FBID}&auction=${AUCTION_ID}&impression=${IMPRESSION_ID}&request=${BID_REQUEST_ID}&bid=${BID_ID}&ortb_loss_code=${AUCTION_LOSS}&clearing_price=${AUCTION_PRICE}"
${AUCTION_LOSS}
: 이는 ORTB 실패 코드로 대체해야 합니다.${AUCTION_PRICE}
: 이는 입찰가와 동일한 단위(예: CPM 기준 USD)를 사용하여 경매의 결제 가격으로 대체해야 합니다.다음은 다양한 실패 코드와 그에 해당하는 실패 이유 리스트입니다.
실패 이유 | 설명 | ORTB v2.5 실패 코드 |
---|---|---|
잘못된 입찰 응답 | 입찰이 유효하지 않습니다(그러나 입찰이 있었고 지연되지 않았으며 nurl을 추출할 수 있을 정도로 유효함). | 3 |
입찰 시간 초과 * | 입찰 응답을 수신하였으나 경매 마감 시간에 늦었습니다. | 2 |
입찰 없음 | 입찰 없음은 HTTP 204(즉, 호출할 nurl이 없음)로 표시되지만 이 응답을 입찰 없음으로 해석할 수 있습니다(통합 문제일 가능성이 큼) 다수의 노출에 입찰을 요청할 수 있고, 전체가 아니라 일부에 입찰합니다. | 9 |
가장 높은 RTB 입찰자가 아님 | 다른 입찰자가 동일한 경매에 참가했다면 인공 입찰(예: RTB가 아닌 거래)을 포함하여 더 나은 입찰가를 제시합니다. | 102 |
재고가 실현되지 않음 | 입찰이 경매에서 낙찰되었으나 노출이 실현되지 않았습니다(예: 페이지가 짧아서 이 슬롯을 포함할 수 없거나 캐시된 광고를 사용하기 전에 사용자가 앱을 나갔습니다). 일부 파트너가 이 광고를 제공할 수 없어서(이벤트가 발생하지 않음) 광고가 제공되지 않을 경우 이를 유추합니다. | 4902 |
광고 서버에 전송됨 | 결정 프로세스에서 마지막 터치포인트가 광고 서버에 높은 입찰가를 전송하는 것일 경우 이를 전송합니다. 행 항목 누락, 광고 서버의 경매 무효화 또는 재고가 실현되지 않는 등으로 인해 노출이 여전히 실패할 수 있습니다. | 4900 |
광고 서버가 RTB 낙찰자를 선택하지 않음 | RTB 경매에 낙찰되었지만 광고 서버가 경매를 무효화했습니다(예: 직접). | 4903 |
낙찰 | 전체 결정 트리가 낙찰되었고 페이지에 태그가 배치되거나(웹) 광고 개체가 캐시되었습니다(앱). 여전히 조회 가능한 노출이 없을 수 있습니다. | 0 |
Audience Network SDK에서 노출 콜백이 트리거될 경우 청구 가능 알림이 필요합니다. burl에 결제 가격을 채워야 합니다.
"https://www.facebook.com/audiencenetwork/burl/?partner=${PARTNER_FBID}&app=${APP_FBID}&placement=${PLACEMENT_FBID}&auction=${AUCTION_ID}&impression=${IMPRESSION_ID}&request=${BID_REQUEST_ID}&bid=${BID_ID}&ortb_loss_code=0&clearing_price=${AUCTION_PRICE}"
${AUCTION_PRICE}
: 이는 입찰가와 동일한 단위(예: CPM 기준 USD)를 사용하여 경매의 결제 가격으로 대체해야 합니다.입찰 시간 초과일 경우 대체 보고 경로를 제공합니다. 입찰이 도착할 때까지 기다리지 않고 호출할 수 있는 일반 nurl입니다. 형식은 다음과 같습니다.
"https://www.facebook.com/audiencenetwork/nurl/?partner=${PARTNER_FBID}&app=${APP_FBID}&auction=${AUCTION_ID}&ortb_loss_code=2"
참고:${PARTNER_FBID}
, ${APP_FBID}
및 ${AUCTION_ID}
는 적절한 값으로 채워야 합니다. 아래의 표는 이러한 값에 대한 설명을 제공합니다.
매개변수 | 유형 | 설명 |
---|---|---|
PARTNER_FBID | 정수 | Facebook에서 발행하는 광고 경매 서버 ID입니다. 전담 광고 경매 파트너가 없다면 여기에 앱 ID를 사용하세요. |
APP_FBID | 정수 | 경매를 시작한 앱/비즈니스의 Facebook 발행 ID입니다. |
AUCTION_ID | 문자열 | 입찰 요청 발행에 사용한 경매의 클라이언트 생성 ID입니다. |
경매를 실행하고 나서 응답 개체를 생성하고 클라이언트 앱에 반환합니다. bid_manager.py
의 샘플에서 경매 서버의 최종 응답을 생성하는 메서드는 다음과 같습니다.
def create_response(bid_response, placement): """Create response object based on the auction result""" ad_format = placement['ad_format'] platform_name = bid_response['platform_name'] platform_placement_id = None for bidding_source_placement_id in placement[ 'bidding_source_placement_ids' ]: if bidding_source_placement_id['platform_name'] == platform_name: platform_placement_id = bidding_source_placement_id[ 'platform_placement_id' ] if platform_placement_id is None: raise InternalError("Platform placement ID not found!") bid_payload = None if platform_name == 'audience_network': bid_payload = bid_response['response'].adm else: raise InternalError("Invalid platform") return (200, { 'placement_id': placement['placement_id'], 'ad_format': ad_format, 'platform_name': platform_name, 'platform_placement_id': platform_placement_id, 'bid_payload': bid_payload, })
마지막으로 샘플 서버는 클라이언트에 대해 다음과 같은 응답을 생성하여 어느 플랫폼을 사용할지 알립니다.
{ 'placement_id': string, // Placement identifier for the auction server 'ad_format': string, // Format of the placement 'platform_name': string, // Which platform won the auction, for example 'audience_network' 'platform_placement_id': string, // Placement ID for the platform, for example the placement ID for Audience network 'bid_payload': string, // The JSON string payload for the platform SDK to load the final ad }